chiark / gitweb /
journal-remote: give names to event sources
[elogind.git] / src / journal-remote / journal-remote.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2012 Zbigniew JÄ™drzejewski-Szmek
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 <errno.h>
23 #include <fcntl.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/prctl.h>
28 #include <sys/socket.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 #include <getopt.h>
33
34 #include "sd-daemon.h"
35 #include "journal-file.h"
36 #include "journald-native.h"
37 #include "socket-util.h"
38 #include "mkdir.h"
39 #include "build.h"
40 #include "macro.h"
41 #include "strv.h"
42 #include "fileio.h"
43 #include "conf-parser.h"
44 #include "siphash24.h"
45
46 #ifdef HAVE_GNUTLS
47 #include <gnutls/gnutls.h>
48 #endif
49
50 #include "journal-remote.h"
51 #include "journal-remote-write.h"
52
53 #define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
54
55 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
56 #define CERT_FILE     CERTIFICATE_ROOT "/certs/journal-remote.pem"
57 #define TRUST_FILE    CERTIFICATE_ROOT "/ca/trusted.pem"
58
59 static char* arg_url = NULL;
60 static char* arg_getter = NULL;
61 static char* arg_listen_raw = NULL;
62 static char* arg_listen_http = NULL;
63 static char* arg_listen_https = NULL;
64 static char** arg_files = NULL;
65 static int arg_compress = true;
66 static int arg_seal = false;
67 static int http_socket = -1, https_socket = -1;
68 static char** arg_gnutls_log = NULL;
69
70 static JournalWriteSplitMode arg_split_mode = JOURNAL_WRITE_SPLIT_HOST;
71 static char* arg_output = NULL;
72
73 static char *arg_key = NULL;
74 static char *arg_cert = NULL;
75 static char *arg_trust = NULL;
76 static bool arg_trust_all = false;
77
78 /**********************************************************************
79  **********************************************************************
80  **********************************************************************/
81
82 static int spawn_child(const char* child, char** argv) {
83         int fd[2];
84         pid_t parent_pid, child_pid;
85         int r;
86
87         if (pipe(fd) < 0) {
88                 log_error("Failed to create pager pipe: %m");
89                 return -errno;
90         }
91
92         parent_pid = getpid();
93
94         child_pid = fork();
95         if (child_pid < 0) {
96                 r = -errno;
97                 log_error("Failed to fork: %m");
98                 safe_close_pair(fd);
99                 return r;
100         }
101
102         /* In the child */
103         if (child_pid == 0) {
104                 r = dup2(fd[1], STDOUT_FILENO);
105                 if (r < 0) {
106                         log_error("Failed to dup pipe to stdout: %m");
107                         _exit(EXIT_FAILURE);
108                 }
109
110                 safe_close_pair(fd);
111
112                 /* Make sure the child goes away when the parent dies */
113                 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
114                         _exit(EXIT_FAILURE);
115
116                 /* Check whether our parent died before we were able
117                  * to set the death signal */
118                 if (getppid() != parent_pid)
119                         _exit(EXIT_SUCCESS);
120
121                 execvp(child, argv);
122                 log_error("Failed to exec child %s: %m", child);
123                 _exit(EXIT_FAILURE);
124         }
125
126         r = close(fd[1]);
127         if (r < 0)
128                 log_warning("Failed to close write end of pipe: %m");
129
130         return fd[0];
131 }
132
133 static int spawn_curl(const char* url) {
134         char **argv = STRV_MAKE("curl",
135                                 "-HAccept: application/vnd.fdo.journal",
136                                 "--silent",
137                                 "--show-error",
138                                 url);
139         int r;
140
141         r = spawn_child("curl", argv);
142         if (r < 0)
143                 log_error("Failed to spawn curl: %m");
144         return r;
145 }
146
147 static int spawn_getter(const char *getter, const char *url) {
148         int r;
149         _cleanup_strv_free_ char **words = NULL;
150
151         assert(getter);
152         r = strv_split_quoted(&words, getter);
153         if (r < 0) {
154                 log_error("Failed to split getter option: %s", strerror(-r));
155                 return r;
156         }
157
158         r = strv_extend(&words, url);
159         if (r < 0) {
160                 log_error("Failed to create command line: %s", strerror(-r));
161                 return r;
162         }
163
164         r = spawn_child(words[0], words);
165         if (r < 0)
166                 log_error("Failed to spawn getter %s: %m", getter);
167
168         return r;
169 }
170
171 #define filename_escape(s) xescape((s), "/ ")
172
173 static int open_output(Writer *w, const char* host) {
174         _cleanup_free_ char *_output = NULL;
175         const char *output;
176         int r;
177
178         switch (arg_split_mode) {
179         case JOURNAL_WRITE_SPLIT_NONE:
180                 output = arg_output ?: REMOTE_JOURNAL_PATH "/remote.journal";
181                 break;
182
183         case JOURNAL_WRITE_SPLIT_HOST: {
184                 _cleanup_free_ char *name;
185
186                 assert(host);
187
188                 name = filename_escape(host);
189                 if (!name)
190                         return log_oom();
191
192                 r = asprintf(&_output, "%s/remote-%s.journal",
193                              arg_output ?: REMOTE_JOURNAL_PATH,
194                              name);
195                 if (r < 0)
196                         return log_oom();
197
198                 output = _output;
199                 break;
200         }
201
202         default:
203                 assert_not_reached("what?");
204         }
205
206         r = journal_file_open_reliably(output,
207                                        O_RDWR|O_CREAT, 0640,
208                                        arg_compress, arg_seal,
209                                        &w->metrics,
210                                        w->mmap,
211                                        NULL, &w->journal);
212         if (r < 0)
213                 log_error("Failed to open output journal %s: %s",
214                           output, strerror(-r));
215         else
216                 log_info("Opened output file %s", w->journal->path);
217         return r;
218 }
219
220 /**********************************************************************
221  **********************************************************************
222  **********************************************************************/
223
224 static int init_writer_hashmap(RemoteServer *s) {
225         static const struct hash_ops *hash_ops[] = {
226                 [JOURNAL_WRITE_SPLIT_NONE] = NULL,
227                 [JOURNAL_WRITE_SPLIT_HOST] = &string_hash_ops,
228         };
229
230         assert(arg_split_mode >= 0 && arg_split_mode < (int) ELEMENTSOF(hash_ops));
231
232         s->writers = hashmap_new(hash_ops[arg_split_mode]);
233         if (!s->writers)
234                 return log_oom();
235
236         return 0;
237 }
238
239 static int get_writer(RemoteServer *s, const char *host,
240                       Writer **writer) {
241         const void *key;
242         _cleanup_writer_unref_ Writer *w = NULL;
243         int r;
244
245         switch(arg_split_mode) {
246         case JOURNAL_WRITE_SPLIT_NONE:
247                 key = "one and only";
248                 break;
249
250         case JOURNAL_WRITE_SPLIT_HOST:
251                 assert(host);
252                 key = host;
253                 break;
254
255         default:
256                 assert_not_reached("what split mode?");
257         }
258
259         w = hashmap_get(s->writers, key);
260         if (w)
261                 writer_ref(w);
262         else {
263                 w = writer_new(s);
264                 if (!w)
265                         return log_oom();
266
267                 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST) {
268                         w->hashmap_key = strdup(key);
269                         if (!w->hashmap_key)
270                                 return log_oom();
271                 }
272
273                 r = open_output(w, host);
274                 if (r < 0)
275                         return r;
276
277                 r = hashmap_put(s->writers, w->hashmap_key ?: key, w);
278                 if (r < 0)
279                         return r;
280         }
281
282         *writer = w;
283         w = NULL;
284         return 0;
285 }
286
287 /**********************************************************************
288  **********************************************************************
289  **********************************************************************/
290
291 /* This should go away as soon as Âµhttpd allows state to be passed around. */
292 static RemoteServer *server;
293
294 static int dispatch_raw_source_event(sd_event_source *event,
295                                      int fd,
296                                      uint32_t revents,
297                                      void *userdata);
298 static int dispatch_blocking_source_event(sd_event_source *event,
299                                           void *userdata);
300 static int dispatch_raw_connection_event(sd_event_source *event,
301                                          int fd,
302                                          uint32_t revents,
303                                          void *userdata);
304 static int dispatch_http_event(sd_event_source *event,
305                                int fd,
306                                uint32_t revents,
307                                void *userdata);
308
309 static int get_source_for_fd(RemoteServer *s,
310                              int fd, char *name, RemoteSource **source) {
311         Writer *writer;
312         int r;
313
314         /* This takes ownership of name, but only on success. */
315
316         assert(fd >= 0);
317         assert(source);
318
319         if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
320                 return log_oom();
321
322         r = get_writer(s, name, &writer);
323         if (r < 0) {
324                 log_warning("Failed to get writer for source %s: %s",
325                             name, strerror(-r));
326                 return r;
327         }
328
329         if (s->sources[fd] == NULL) {
330                 s->sources[fd] = source_new(fd, false, name, writer);
331                 if (!s->sources[fd]) {
332                         writer_unref(writer);
333                         return log_oom();
334                 }
335
336                 s->active++;
337         }
338
339         *source = s->sources[fd];
340         return 0;
341 }
342
343 static int remove_source(RemoteServer *s, int fd) {
344         RemoteSource *source;
345
346         assert(s);
347         assert(fd >= 0 && fd < (ssize_t) s->sources_size);
348
349         source = s->sources[fd];
350         if (source) {
351                 /* this closes fd too */
352                 source_free(source);
353                 s->sources[fd] = NULL;
354                 s->active--;
355         }
356
357         return 0;
358 }
359
360 static int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
361
362         RemoteSource *source;
363         int r;
364
365         /* This takes ownership of name, even on failure, if own_name is true. */
366
367         assert(s);
368         assert(fd >= 0);
369         assert(name);
370
371         if (!own_name) {
372                 name = strdup(name);
373                 if (!name)
374                         return log_oom();
375         }
376
377         r = get_source_for_fd(s, fd, name, &source);
378         if (r < 0) {
379                 log_error("Failed to create source for fd:%d (%s): %s",
380                           fd, name, strerror(-r));
381                 free(name);
382                 return r;
383         }
384
385         r = sd_event_add_io(s->events, &source->event,
386                             fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
387                             dispatch_raw_source_event, s);
388         if (r == -EPERM) {
389                 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd, name);
390                 r = sd_event_add_defer(s->events, &source->event,
391                                        dispatch_blocking_source_event, source);
392                 if (r == 0)
393                         sd_event_source_set_enabled(source->event, SD_EVENT_ON);
394         }
395         if (r < 0) {
396                 log_error("Failed to register event source for fd:%d: %s",
397                           fd, strerror(-r));
398                 goto error;
399         }
400
401         r = sd_event_source_set_name(source->event, name);
402         if (r < 0) {
403                 log_error("Failed to set source name for fd:%d: %s", fd, strerror(-r));
404                 goto error;
405         }
406
407         return 1; /* work to do */
408
409  error:
410         remove_source(s, fd);
411         return r;
412 }
413
414 static int add_raw_socket(RemoteServer *s, int fd) {
415         int r;
416         _cleanup_close_ int fd_ = fd;
417         char name[strlen("raw-socket-") + DECIMAL_STR_MAX(int)];
418
419         assert(fd >= 0);
420
421         r = sd_event_add_io(s->events, &s->listen_event,
422                             fd, EPOLLIN,
423                             dispatch_raw_connection_event, s);
424         if (r < 0)
425                 return r;
426
427         snprintf(name, sizeof(name), "raw-socket-%d", fd);
428
429         r = sd_event_source_set_name(s->listen_event, name);
430         if (r < 0)
431                 return r;
432
433         fd_ = -1;
434         s->active ++;
435         return 0;
436 }
437
438 static int setup_raw_socket(RemoteServer *s, const char *address) {
439         int fd;
440
441         fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
442         if (fd < 0)
443                 return fd;
444
445         return add_raw_socket(s, fd);
446 }
447
448 /**********************************************************************
449  **********************************************************************
450  **********************************************************************/
451
452 static RemoteSource *request_meta(void **connection_cls, int fd, char *hostname) {
453         RemoteSource *source;
454         Writer *writer;
455         int r;
456
457         assert(connection_cls);
458         if (*connection_cls)
459                 return *connection_cls;
460
461         r = get_writer(server, hostname, &writer);
462         if (r < 0) {
463                 log_warning("Failed to get writer for source %s: %s",
464                             hostname, strerror(-r));
465                 return NULL;
466         }
467
468         source = source_new(fd, true, hostname, writer);
469         if (!source) {
470                 log_oom();
471                 writer_unref(writer);
472                 return NULL;
473         }
474
475         log_debug("Added RemoteSource as connection metadata %p", source);
476
477         *connection_cls = source;
478         return source;
479 }
480
481 static void request_meta_free(void *cls,
482                               struct MHD_Connection *connection,
483                               void **connection_cls,
484                               enum MHD_RequestTerminationCode toe) {
485         RemoteSource *s;
486
487         assert(connection_cls);
488         s = *connection_cls;
489
490         log_debug("Cleaning up connection metadata %p", s);
491         source_free(s);
492         *connection_cls = NULL;
493 }
494
495 static int process_http_upload(
496                 struct MHD_Connection *connection,
497                 const char *upload_data,
498                 size_t *upload_data_size,
499                 RemoteSource *source) {
500
501         bool finished = false;
502         size_t remaining;
503         int r;
504
505         assert(source);
506
507         log_debug("request_handler_upload: connection %p, %zu bytes",
508                   connection, *upload_data_size);
509
510         if (*upload_data_size) {
511                 log_debug("Received %zu bytes", *upload_data_size);
512
513                 r = push_data(source, upload_data, *upload_data_size);
514                 if (r < 0)
515                         return mhd_respond_oom(connection);
516
517                 *upload_data_size = 0;
518         } else
519                 finished = true;
520
521         while (true) {
522                 r = process_source(source, arg_compress, arg_seal);
523                 if (r == -EAGAIN || r == -EWOULDBLOCK)
524                         break;
525                 else if (r < 0) {
526                         log_warning("Failed to process data for connection %p", connection);
527                         if (r == -E2BIG)
528                                 return mhd_respondf(connection,
529                                                     MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
530                                                     "Entry is too large, maximum is %u bytes.\n",
531                                                     DATA_SIZE_MAX);
532                         else
533                                 return mhd_respondf(connection,
534                                                     MHD_HTTP_UNPROCESSABLE_ENTITY,
535                                                     "Processing failed: %s.", strerror(-r));
536                 }
537         }
538
539         if (!finished)
540                 return MHD_YES;
541
542         /* The upload is finished */
543
544         remaining = source_non_empty(source);
545         if (remaining > 0) {
546                 log_warning("Premature EOFbyte. %zu bytes lost.", remaining);
547                 return mhd_respondf(connection, MHD_HTTP_EXPECTATION_FAILED,
548                                     "Premature EOF. %zu bytes of trailing data not processed.",
549                                     remaining);
550         }
551
552         return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
553 };
554
555 static int request_handler(
556                 void *cls,
557                 struct MHD_Connection *connection,
558                 const char *url,
559                 const char *method,
560                 const char *version,
561                 const char *upload_data,
562                 size_t *upload_data_size,
563                 void **connection_cls) {
564
565         const char *header;
566         int r, code, fd;
567         _cleanup_free_ char *hostname = NULL;
568
569         assert(connection);
570         assert(connection_cls);
571         assert(url);
572         assert(method);
573
574         log_debug("Handling a connection %s %s %s", method, url, version);
575
576         if (*connection_cls)
577                 return process_http_upload(connection,
578                                            upload_data, upload_data_size,
579                                            *connection_cls);
580
581         if (!streq(method, "POST"))
582                 return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
583                                    "Unsupported method.\n");
584
585         if (!streq(url, "/upload"))
586                 return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
587                                    "Not found.\n");
588
589         header = MHD_lookup_connection_value(connection,
590                                              MHD_HEADER_KIND, "Content-Type");
591         if (!header || !streq(header, "application/vnd.fdo.journal"))
592                 return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
593                                    "Content-Type: application/vnd.fdo.journal"
594                                    " is required.\n");
595
596         {
597                 const union MHD_ConnectionInfo *ci;
598
599                 ci = MHD_get_connection_info(connection,
600                                              MHD_CONNECTION_INFO_CONNECTION_FD);
601                 if (!ci) {
602                         log_error("MHD_get_connection_info failed: cannot get remote fd");
603                         return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
604                                            "Cannot check remote address");
605                 }
606
607                 fd = ci->connect_fd;
608                 assert(fd >= 0);
609         }
610
611         if (server->check_trust) {
612                 r = check_permissions(connection, &code, &hostname);
613                 if (r < 0)
614                         return code;
615         } else {
616                 r = getnameinfo_pretty(fd, &hostname);
617                 if (r < 0) {
618                         return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
619                                            "Cannot check remote hostname");
620                 }
621         }
622
623         assert(hostname);
624
625         if (!request_meta(connection_cls, fd, hostname))
626                 return respond_oom(connection);
627         hostname = NULL;
628         return MHD_YES;
629 }
630
631 static int setup_microhttpd_server(RemoteServer *s,
632                                    int fd,
633                                    const char *key,
634                                    const char *cert,
635                                    const char *trust) {
636         struct MHD_OptionItem opts[] = {
637                 { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
638                 { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
639                 { MHD_OPTION_LISTEN_SOCKET, fd},
640                 { MHD_OPTION_END},
641                 { MHD_OPTION_END},
642                 { MHD_OPTION_END},
643                 { MHD_OPTION_END}};
644         int opts_pos = 3;
645         int flags =
646                 MHD_USE_DEBUG |
647                 MHD_USE_PEDANTIC_CHECKS |
648                 MHD_USE_EPOLL_LINUX_ONLY |
649                 MHD_USE_DUAL_STACK;
650
651         const union MHD_DaemonInfo *info;
652         int r, epoll_fd;
653         MHDDaemonWrapper *d;
654
655         assert(fd >= 0);
656
657         r = fd_nonblock(fd, true);
658         if (r < 0) {
659                 log_error("Failed to make fd:%d nonblocking: %s", fd, strerror(-r));
660                 return r;
661         }
662
663         if (key) {
664                 assert(cert);
665
666                 opts[opts_pos++] = (struct MHD_OptionItem)
667                         {MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
668                 opts[opts_pos++] = (struct MHD_OptionItem)
669                         {MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
670
671                 flags |= MHD_USE_SSL;
672
673                 if (trust)
674                         opts[opts_pos++] = (struct MHD_OptionItem)
675                                 {MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
676         }
677
678         d = new(MHDDaemonWrapper, 1);
679         if (!d)
680                 return log_oom();
681
682         d->fd = (uint64_t) fd;
683
684         d->daemon = MHD_start_daemon(flags, 0,
685                                      NULL, NULL,
686                                      request_handler, NULL,
687                                      MHD_OPTION_ARRAY, opts,
688                                      MHD_OPTION_END);
689         if (!d->daemon) {
690                 log_error("Failed to start Âµhttp daemon");
691                 r = -EINVAL;
692                 goto error;
693         }
694
695         log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
696                   key ? "HTTPS" : "HTTP", fd, d);
697
698
699         info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
700         if (!info) {
701                 log_error("µhttp returned NULL daemon info");
702                 r = -ENOTSUP;
703                 goto error;
704         }
705
706         epoll_fd = info->listen_fd;
707         if (epoll_fd < 0) {
708                 log_error("µhttp epoll fd is invalid");
709                 r = -EUCLEAN;
710                 goto error;
711         }
712
713         r = sd_event_add_io(s->events, &d->event,
714                             epoll_fd, EPOLLIN,
715                             dispatch_http_event, d);
716         if (r < 0) {
717                 log_error("Failed to add event callback: %s", strerror(-r));
718                 goto error;
719         }
720
721         r = sd_event_source_set_name(d->event, "epoll-fd");
722         if (r < 0) {
723                 log_error("Failed to set source name: %s", strerror(-r));
724                 goto error;
725         }
726
727         r = hashmap_ensure_allocated(&s->daemons, &uint64_hash_ops);
728         if (r < 0) {
729                 log_oom();
730                 goto error;
731         }
732
733         r = hashmap_put(s->daemons, &d->fd, d);
734         if (r < 0) {
735                 log_error("Failed to add daemon to hashmap: %s", strerror(-r));
736                 goto error;
737         }
738
739         s->active ++;
740         return 0;
741
742 error:
743         MHD_stop_daemon(d->daemon);
744         free(d->daemon);
745         free(d);
746         return r;
747 }
748
749 static int setup_microhttpd_socket(RemoteServer *s,
750                                    const char *address,
751                                    const char *key,
752                                    const char *cert,
753                                    const char *trust) {
754         int fd;
755
756         fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
757         if (fd < 0)
758                 return fd;
759
760         return setup_microhttpd_server(s, fd, key, cert, trust);
761 }
762
763 static int dispatch_http_event(sd_event_source *event,
764                                int fd,
765                                uint32_t revents,
766                                void *userdata) {
767         MHDDaemonWrapper *d = userdata;
768         int r;
769
770         assert(d);
771
772         r = MHD_run(d->daemon);
773         if (r == MHD_NO) {
774                 log_error("MHD_run failed!");
775                 // XXX: unregister daemon
776                 return -EINVAL;
777         }
778
779         return 1; /* work to do */
780 }
781
782 /**********************************************************************
783  **********************************************************************
784  **********************************************************************/
785
786 static int setup_signals(RemoteServer *s) {
787         sigset_t mask;
788         int r;
789
790         assert(s);
791
792         assert_se(sigemptyset(&mask) == 0);
793         sigset_add_many(&mask, SIGINT, SIGTERM, -1);
794         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
795
796         r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, NULL, s);
797         if (r < 0)
798                 return r;
799
800         r = sd_event_source_set_name(s->sigterm_event, "sigterm");
801         if (r < 0)
802                 return r;
803
804         r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, NULL, s);
805         if (r < 0)
806                 return r;
807
808         r = sd_event_source_set_name(s->sigint_event, "sigint");
809         if (r < 0)
810                 return r;
811
812         return 0;
813 }
814
815 static int negative_fd(const char *spec) {
816         /* Return a non-positive number as its inverse, -EINVAL otherwise. */
817
818         int fd, r;
819
820         r = safe_atoi(spec, &fd);
821         if (r < 0)
822                 return r;
823
824         if (fd > 0)
825                 return -EINVAL;
826         else
827                 return -fd;
828 }
829
830 static int remoteserver_init(RemoteServer *s,
831                              const char* key,
832                              const char* cert,
833                              const char* trust) {
834         int r, n, fd;
835         char **file;
836
837         assert(s);
838
839         if ((arg_listen_raw || arg_listen_http) && trust) {
840                 log_error("Option --trust makes all non-HTTPS connections untrusted.");
841                 return -EINVAL;
842         }
843
844         r = sd_event_default(&s->events);
845         if (r < 0) {
846                 log_error("Failed to allocate event loop: %s", strerror(-r));
847                 return r;
848         }
849
850         setup_signals(s);
851
852         assert(server == NULL);
853         server = s;
854
855         r = init_writer_hashmap(s);
856         if (r < 0)
857                 return r;
858
859         n = sd_listen_fds(true);
860         if (n < 0) {
861                 log_error("Failed to read listening file descriptors from environment: %s",
862                           strerror(-n));
863                 return n;
864         } else
865                 log_info("Received %d descriptors", n);
866
867         if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
868                 log_error("Received fewer sockets than expected");
869                 return -EBADFD;
870         }
871
872         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
873                 if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
874                         log_info("Received a listening socket (fd:%d)", fd);
875
876                         if (fd == http_socket)
877                                 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
878                         else if (fd == https_socket)
879                                 r = setup_microhttpd_server(s, fd, key, cert, trust);
880                         else
881                                 r = add_raw_socket(s, fd);
882                 } else if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
883                         char *hostname;
884
885                         r = getnameinfo_pretty(fd, &hostname);
886                         if (r < 0) {
887                                 log_error("Failed to retrieve remote name: %s", strerror(-r));
888                                 return r;
889                         }
890
891                         log_info("Received a connection socket (fd:%d) from %s", fd, hostname);
892
893                         r = add_source(s, fd, hostname, true);
894                 } else {
895                         log_error("Unknown socket passed on fd:%d", fd);
896
897                         return -EINVAL;
898                 }
899
900                 if(r < 0) {
901                         log_error("Failed to register socket (fd:%d): %s",
902                                   fd, strerror(-r));
903                         return r;
904                 }
905         }
906
907         if (arg_url) {
908                 const char *url, *hostname;
909
910                 url = strappenda(arg_url, "/entries");
911
912                 if (arg_getter) {
913                         log_info("Spawning getter %s...", url);
914                         fd = spawn_getter(arg_getter, url);
915                 } else {
916                         log_info("Spawning curl %s...", url);
917                         fd = spawn_curl(url);
918                 }
919                 if (fd < 0)
920                         return fd;
921
922                 hostname =
923                         startswith(arg_url, "https://") ?:
924                         startswith(arg_url, "http://") ?:
925                         arg_url;
926
927                 r = add_source(s, fd, (char*) hostname, false);
928                 if (r < 0)
929                         return r;
930         }
931
932         if (arg_listen_raw) {
933                 log_info("Listening on a socket...");
934                 r = setup_raw_socket(s, arg_listen_raw);
935                 if (r < 0)
936                         return r;
937         }
938
939         if (arg_listen_http) {
940                 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
941                 if (r < 0)
942                         return r;
943         }
944
945         if (arg_listen_https) {
946                 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
947                 if (r < 0)
948                         return r;
949         }
950
951         STRV_FOREACH(file, arg_files) {
952                 const char *output_name;
953
954                 if (streq(*file, "-")) {
955                         log_info("Using standard input as source.");
956
957                         fd = STDIN_FILENO;
958                         output_name = "stdin";
959                 } else {
960                         log_info("Reading file %s...", *file);
961
962                         fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
963                         if (fd < 0) {
964                                 log_error("Failed to open %s: %m", *file);
965                                 return -errno;
966                         }
967                         output_name = *file;
968                 }
969
970                 r = add_source(s, fd, (char*) output_name, false);
971                 if (r < 0)
972                         return r;
973         }
974
975         if (s->active == 0) {
976                 log_error("Zarro sources specified");
977                 return -EINVAL;
978         }
979
980         if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) {
981                 /* In this case we know what the writer will be
982                    called, so we can create it and verify that we can
983                    create output as expected. */
984                 r = get_writer(s, NULL, &s->_single_writer);
985                 if (r < 0)
986                         return r;
987         }
988
989         return 0;
990 }
991
992 static void server_destroy(RemoteServer *s) {
993         size_t i;
994         MHDDaemonWrapper *d;
995
996         while ((d = hashmap_steal_first(s->daemons))) {
997                 MHD_stop_daemon(d->daemon);
998                 sd_event_source_unref(d->event);
999                 free(d);
1000         }
1001
1002         hashmap_free(s->daemons);
1003
1004         assert(s->sources_size == 0 || s->sources);
1005         for (i = 0; i < s->sources_size; i++)
1006                 remove_source(s, i);
1007         free(s->sources);
1008
1009         writer_unref(s->_single_writer);
1010         hashmap_free(s->writers);
1011
1012         sd_event_source_unref(s->sigterm_event);
1013         sd_event_source_unref(s->sigint_event);
1014         sd_event_source_unref(s->listen_event);
1015         sd_event_unref(s->events);
1016
1017         /* fds that we're listening on remain open... */
1018 }
1019
1020 /**********************************************************************
1021  **********************************************************************
1022  **********************************************************************/
1023
1024 static int dispatch_raw_source_event(sd_event_source *event,
1025                                      int fd,
1026                                      uint32_t revents,
1027                                      void *userdata) {
1028
1029         RemoteServer *s = userdata;
1030         RemoteSource *source;
1031         int r;
1032
1033         assert(fd >= 0 && fd < (ssize_t) s->sources_size);
1034         source = s->sources[fd];
1035         assert(source->fd == fd);
1036
1037         r = process_source(source, arg_compress, arg_seal);
1038         if (source->state == STATE_EOF) {
1039                 size_t remaining;
1040
1041                 log_info("EOF reached with source fd:%d (%s)",
1042                          source->fd, source->name);
1043
1044                 remaining = source_non_empty(source);
1045                 if (remaining > 0)
1046                         log_warning("Premature EOF. %zu bytes lost.", remaining);
1047                 remove_source(s, source->fd);
1048                 log_info("%zd active sources remaining", s->active);
1049                 return 0;
1050         } else if (r == -E2BIG) {
1051                 log_error("Entry too big, skipped");
1052                 return 1;
1053         } else if (r == -EAGAIN) {
1054                 return 0;
1055         } else if (r < 0) {
1056                 log_info("Closing connection: %s", strerror(-r));
1057                 remove_source(server, fd);
1058                 return 0;
1059         } else
1060                 return 1;
1061 }
1062
1063 static int dispatch_blocking_source_event(sd_event_source *event,
1064                                           void *userdata) {
1065         RemoteSource *source = userdata;
1066
1067         return dispatch_raw_source_event(event, source->fd, EPOLLIN, server);
1068 }
1069
1070 static int accept_connection(const char* type, int fd,
1071                              SocketAddress *addr, char **hostname) {
1072         int fd2, r;
1073
1074         log_debug("Accepting new %s connection on fd:%d", type, fd);
1075         fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
1076         if (fd2 < 0) {
1077                 log_error("accept() on fd:%d failed: %m", fd);
1078                 return -errno;
1079         }
1080
1081         switch(socket_address_family(addr)) {
1082         case AF_INET:
1083         case AF_INET6: {
1084                 _cleanup_free_ char *a = NULL;
1085                 char *b;
1086
1087                 r = socket_address_print(addr, &a);
1088                 if (r < 0) {
1089                         log_error("socket_address_print(): %s", strerror(-r));
1090                         close(fd2);
1091                         return r;
1092                 }
1093
1094                 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
1095                 if (r < 0) {
1096                         close(fd2);
1097                         return r;
1098                 }
1099
1100                 log_info("Accepted %s %s connection from %s",
1101                          type,
1102                          socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
1103                          a);
1104
1105                 *hostname = b;
1106
1107                 return fd2;
1108         };
1109         default:
1110                 log_error("Rejected %s connection with unsupported family %d",
1111                           type, socket_address_family(addr));
1112                 close(fd2);
1113
1114                 return -EINVAL;
1115         }
1116 }
1117
1118 static int dispatch_raw_connection_event(sd_event_source *event,
1119                                          int fd,
1120                                          uint32_t revents,
1121                                          void *userdata) {
1122         RemoteServer *s = userdata;
1123         int fd2;
1124         SocketAddress addr = {
1125                 .size = sizeof(union sockaddr_union),
1126                 .type = SOCK_STREAM,
1127         };
1128         char *hostname;
1129
1130         fd2 = accept_connection("raw", fd, &addr, &hostname);
1131         if (fd2 < 0)
1132                 return fd2;
1133
1134         return add_source(s, fd2, hostname, true);
1135 }
1136
1137 /**********************************************************************
1138  **********************************************************************
1139  **********************************************************************/
1140
1141 static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
1142         [JOURNAL_WRITE_SPLIT_NONE] = "none",
1143         [JOURNAL_WRITE_SPLIT_HOST] = "host",
1144 };
1145
1146 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
1147 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
1148                                 journal_write_split_mode,
1149                                 JournalWriteSplitMode,
1150                                 "Failed to parse split mode setting");
1151
1152 static int parse_config(void) {
1153         const ConfigTableItem items[] = {
1154                 { "Remote",  "SplitMode",              config_parse_write_split_mode, 0, &arg_split_mode },
1155                 { "Remote",  "ServerKeyFile",          config_parse_path,             0, &arg_key        },
1156                 { "Remote",  "ServerCertificateFile",  config_parse_path,             0, &arg_cert       },
1157                 { "Remote",  "TrustedCertificateFile", config_parse_path,             0, &arg_trust      },
1158                 {}};
1159
1160         return config_parse(NULL, PKGSYSCONFDIR "/journal-remote.conf", NULL,
1161                             "Remote\0",
1162                             config_item_table_lookup, items,
1163                             false, false, true, NULL);
1164 }
1165
1166 static void help(void) {
1167         printf("%s [OPTIONS...] {FILE|-}...\n\n"
1168                "Write external journal events to journal file(s).\n\n"
1169                "  -h --help               Show this help\n"
1170                "     --version            Show package version\n"
1171                "     --url=URL            Read events from systemd-journal-gatewayd at URL\n"
1172                "     --getter=COMMAND     Read events from the output of COMMAND\n"
1173                "     --listen-raw=ADDR    Listen for connections at ADDR\n"
1174                "     --listen-http=ADDR   Listen for HTTP connections at ADDR\n"
1175                "     --listen-https=ADDR  Listen for HTTPS connections at ADDR\n"
1176                "  -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1177                "     --compress[=BOOL]    Use XZ-compression in the output journal (default: yes)\n"
1178                "     --seal[=BOOL]        Use Event sealing in the output journal (default: no)\n"
1179                "     --key=FILENAME       Specify key in PEM format (default:\n"
1180                "                          \"" PRIV_KEY_FILE "\")\n"
1181                "     --cert=FILENAME      Specify certificate in PEM format (default:\n"
1182                "                          \"" CERT_FILE "\")\n"
1183                "     --trust=FILENAME|all Specify CA certificate or disable checking (default:\n"
1184                "                          \"" TRUST_FILE "\")\n"
1185                "     --gnutls-log=CATEGORY...\n"
1186                "                          Specify a list of gnutls logging categories\n"
1187                "\n"
1188                "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1189                , program_invocation_short_name);
1190 }
1191
1192 static int parse_argv(int argc, char *argv[]) {
1193         enum {
1194                 ARG_VERSION = 0x100,
1195                 ARG_URL,
1196                 ARG_LISTEN_RAW,
1197                 ARG_LISTEN_HTTP,
1198                 ARG_LISTEN_HTTPS,
1199                 ARG_GETTER,
1200                 ARG_SPLIT_MODE,
1201                 ARG_COMPRESS,
1202                 ARG_SEAL,
1203                 ARG_KEY,
1204                 ARG_CERT,
1205                 ARG_TRUST,
1206                 ARG_GNUTLS_LOG,
1207         };
1208
1209         static const struct option options[] = {
1210                 { "help",         no_argument,       NULL, 'h'              },
1211                 { "version",      no_argument,       NULL, ARG_VERSION      },
1212                 { "url",          required_argument, NULL, ARG_URL          },
1213                 { "getter",       required_argument, NULL, ARG_GETTER       },
1214                 { "listen-raw",   required_argument, NULL, ARG_LISTEN_RAW   },
1215                 { "listen-http",  required_argument, NULL, ARG_LISTEN_HTTP  },
1216                 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1217                 { "output",       required_argument, NULL, 'o'              },
1218                 { "split-mode",   required_argument, NULL, ARG_SPLIT_MODE   },
1219                 { "compress",     optional_argument, NULL, ARG_COMPRESS     },
1220                 { "seal",         optional_argument, NULL, ARG_SEAL         },
1221                 { "key",          required_argument, NULL, ARG_KEY          },
1222                 { "cert",         required_argument, NULL, ARG_CERT         },
1223                 { "trust",        required_argument, NULL, ARG_TRUST        },
1224                 { "gnutls-log",   required_argument, NULL, ARG_GNUTLS_LOG   },
1225                 {}
1226         };
1227
1228         int c, r;
1229         bool type_a, type_b;
1230
1231         assert(argc >= 0);
1232         assert(argv);
1233
1234         while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1235                 switch(c) {
1236                 case 'h':
1237                         help();
1238                         return 0 /* done */;
1239
1240                 case ARG_VERSION:
1241                         puts(PACKAGE_STRING);
1242                         puts(SYSTEMD_FEATURES);
1243                         return 0 /* done */;
1244
1245                 case ARG_URL:
1246                         if (arg_url) {
1247                                 log_error("cannot currently set more than one --url");
1248                                 return -EINVAL;
1249                         }
1250
1251                         arg_url = optarg;
1252                         break;
1253
1254                 case ARG_GETTER:
1255                         if (arg_getter) {
1256                                 log_error("cannot currently use --getter more than once");
1257                                 return -EINVAL;
1258                         }
1259
1260                         arg_getter = optarg;
1261                         break;
1262
1263                 case ARG_LISTEN_RAW:
1264                         if (arg_listen_raw) {
1265                                 log_error("cannot currently use --listen-raw more than once");
1266                                 return -EINVAL;
1267                         }
1268
1269                         arg_listen_raw = optarg;
1270                         break;
1271
1272                 case ARG_LISTEN_HTTP:
1273                         if (arg_listen_http || http_socket >= 0) {
1274                                 log_error("cannot currently use --listen-http more than once");
1275                                 return -EINVAL;
1276                         }
1277
1278                         r = negative_fd(optarg);
1279                         if (r >= 0)
1280                                 http_socket = r;
1281                         else
1282                                 arg_listen_http = optarg;
1283                         break;
1284
1285                 case ARG_LISTEN_HTTPS:
1286                         if (arg_listen_https || https_socket >= 0) {
1287                                 log_error("cannot currently use --listen-https more than once");
1288                                 return -EINVAL;
1289                         }
1290
1291                         r = negative_fd(optarg);
1292                         if (r >= 0)
1293                                 https_socket = r;
1294                         else
1295                                 arg_listen_https = optarg;
1296
1297                         break;
1298
1299                 case ARG_KEY:
1300                         if (arg_key) {
1301                                 log_error("Key file specified twice");
1302                                 return -EINVAL;
1303                         }
1304
1305                         arg_key = strdup(optarg);
1306                         if (!arg_key)
1307                                 return log_oom();
1308
1309                         break;
1310
1311                 case ARG_CERT:
1312                         if (arg_cert) {
1313                                 log_error("Certificate file specified twice");
1314                                 return -EINVAL;
1315                         }
1316
1317                         arg_cert = strdup(optarg);
1318                         if (!arg_cert)
1319                                 return log_oom();
1320
1321                         break;
1322
1323                 case ARG_TRUST:
1324                         if (arg_trust || arg_trust_all) {
1325                                 log_error("Confusing trusted CA configuration");
1326                                 return -EINVAL;
1327                         }
1328
1329                         if (streq(optarg, "all"))
1330                                 arg_trust_all = true;
1331                         else {
1332 #ifdef HAVE_GNUTLS
1333                                 arg_trust = strdup(optarg);
1334                                 if (!arg_trust)
1335                                         return log_oom();
1336 #else
1337                                 log_error("Option --trust is not available.");
1338                                 return -EINVAL;
1339 #endif
1340                         }
1341
1342                         break;
1343
1344                 case 'o':
1345                         if (arg_output) {
1346                                 log_error("cannot use --output/-o more than once");
1347                                 return -EINVAL;
1348                         }
1349
1350                         arg_output = optarg;
1351                         break;
1352
1353                 case ARG_SPLIT_MODE:
1354                         arg_split_mode = journal_write_split_mode_from_string(optarg);
1355                         if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) {
1356                                 log_error("Invalid split mode: %s", optarg);
1357                                 return -EINVAL;
1358                         }
1359                         break;
1360
1361                 case ARG_COMPRESS:
1362                         if (optarg) {
1363                                 r = parse_boolean(optarg);
1364                                 if (r < 0) {
1365                                         log_error("Failed to parse --compress= parameter.");
1366                                         return -EINVAL;
1367                                 }
1368
1369                                 arg_compress = !!r;
1370                         } else
1371                                 arg_compress = true;
1372
1373                         break;
1374
1375                 case ARG_SEAL:
1376                         if (optarg) {
1377                                 r = parse_boolean(optarg);
1378                                 if (r < 0) {
1379                                         log_error("Failed to parse --seal= parameter.");
1380                                         return -EINVAL;
1381                                 }
1382
1383                                 arg_seal = !!r;
1384                         } else
1385                                 arg_seal = true;
1386
1387                         break;
1388
1389                 case ARG_GNUTLS_LOG: {
1390 #ifdef HAVE_GNUTLS
1391                         const char *word, *state;
1392                         size_t size;
1393
1394                         FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
1395                                 char *cat;
1396
1397                                 cat = strndup(word, size);
1398                                 if (!cat)
1399                                         return log_oom();
1400
1401                                 if (strv_consume(&arg_gnutls_log, cat) < 0)
1402                                         return log_oom();
1403                         }
1404                         break;
1405 #else
1406                         log_error("Option --gnutls-log is not available.");
1407                         return -EINVAL;
1408 #endif
1409                 }
1410
1411                 case '?':
1412                         return -EINVAL;
1413
1414                 default:
1415                         assert_not_reached("Unknown option code.");
1416                 }
1417
1418         if (optind < argc)
1419                 arg_files = argv + optind;
1420
1421         type_a = arg_getter || !strv_isempty(arg_files);
1422         type_b = arg_url
1423                 || arg_listen_raw
1424                 || arg_listen_http || arg_listen_https
1425                 || sd_listen_fds(false) > 0;
1426         if (type_a && type_b) {
1427                 log_error("Cannot use file input or --getter with "
1428                           "--arg-listen-... or socket activation.");
1429                 return -EINVAL;
1430         }
1431         if (type_a) {
1432                 if (!arg_output) {
1433                         log_error("Option --output must be specified with file input or --getter.");
1434                         return -EINVAL;
1435                 }
1436
1437                 arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
1438         }
1439
1440         if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE
1441             && arg_output && is_dir(arg_output, true) > 0) {
1442                 log_error("For SplitMode=none, output must be a file.");
1443                 return -EINVAL;
1444         }
1445
1446         if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
1447             && arg_output && is_dir(arg_output, true) <= 0) {
1448                 log_error("For SplitMode=host, output must be a directory.");
1449                 return -EINVAL;
1450         }
1451
1452         log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1453                   journal_write_split_mode_to_string(arg_split_mode),
1454                   strna(arg_key),
1455                   strna(arg_cert),
1456                   strna(arg_trust));
1457
1458         return 1 /* work to do */;
1459 }
1460
1461 static int load_certificates(char **key, char **cert, char **trust) {
1462         int r;
1463
1464         r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
1465         if (r < 0) {
1466                 log_error("Failed to read key from file '%s': %s",
1467                           arg_key ?: PRIV_KEY_FILE, strerror(-r));
1468                 return r;
1469         }
1470
1471         r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1472         if (r < 0) {
1473                 log_error("Failed to read certificate from file '%s': %s",
1474                           arg_cert ?: CERT_FILE, strerror(-r));
1475                 return r;
1476         }
1477
1478         if (arg_trust_all)
1479                 log_info("Certificate checking disabled.");
1480         else {
1481                 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1482                 if (r < 0) {
1483                         log_error("Failed to read CA certificate file '%s': %s",
1484                                   arg_trust ?: TRUST_FILE, strerror(-r));
1485                         return r;
1486                 }
1487         }
1488
1489         return 0;
1490 }
1491
1492 static int setup_gnutls_logger(char **categories) {
1493         if (!arg_listen_http && !arg_listen_https)
1494                 return 0;
1495
1496 #ifdef HAVE_GNUTLS
1497         {
1498                 char **cat;
1499                 int r;
1500
1501                 gnutls_global_set_log_function(log_func_gnutls);
1502
1503                 if (categories)
1504                         STRV_FOREACH(cat, categories) {
1505                                 r = log_enable_gnutls_category(*cat);
1506                                 if (r < 0)
1507                                         return r;
1508                         }
1509                 else
1510                         log_reset_gnutls_level();
1511         }
1512 #endif
1513
1514         return 0;
1515 }
1516
1517 int main(int argc, char **argv) {
1518         RemoteServer s = {};
1519         int r;
1520         _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1521
1522         log_show_color(true);
1523         log_parse_environment();
1524
1525         r = parse_config();
1526         if (r < 0)
1527                 return EXIT_FAILURE;
1528
1529         r = parse_argv(argc, argv);
1530         if (r <= 0)
1531                 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1532
1533         r = setup_gnutls_logger(arg_gnutls_log);
1534         if (r < 0)
1535                 return EXIT_FAILURE;
1536
1537         if (arg_listen_https || https_socket >= 0)
1538                 if (load_certificates(&key, &cert, &trust) < 0)
1539                         return EXIT_FAILURE;
1540
1541         if (remoteserver_init(&s, key, cert, trust) < 0)
1542                 return EXIT_FAILURE;
1543
1544         sd_event_set_watchdog(s.events, true);
1545
1546         log_debug("%s running as pid "PID_FMT,
1547                   program_invocation_short_name, getpid());
1548         sd_notify(false,
1549                   "READY=1\n"
1550                   "STATUS=Processing requests...");
1551
1552         while (s.active) {
1553                 r = sd_event_get_state(s.events);
1554                 if (r < 0)
1555                         break;
1556                 if (r == SD_EVENT_FINISHED)
1557                         break;
1558
1559                 r = sd_event_run(s.events, -1);
1560                 if (r < 0) {
1561                         log_error("Failed to run event loop: %s", strerror(-r));
1562                         break;
1563                 }
1564         }
1565
1566         sd_notifyf(false,
1567                    "STOPPING=1\n"
1568                    "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
1569         log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
1570
1571         server_destroy(&s);
1572
1573         free(arg_key);
1574         free(arg_cert);
1575         free(arg_trust);
1576
1577         return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1578 }