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