chiark / gitweb /
c97cfe613e86201f21e61ad179e2f7ec8b54279d
[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         assert(fd >= 0);
315         assert(source);
316
317         if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
318                 return log_oom();
319
320         r = get_writer(s, name, &writer);
321         if (r < 0) {
322                 log_warning("Failed to get writer for source %s: %s",
323                             name, strerror(-r));
324                 return r;
325         }
326
327         if (s->sources[fd] == NULL) {
328                 s->sources[fd] = source_new(fd, false, name, writer);
329                 if (!s->sources[fd]) {
330                         writer_unref(writer);
331                         return log_oom();
332                 }
333
334                 s->active++;
335         }
336
337         *source = s->sources[fd];
338         return 0;
339 }
340
341 static int remove_source(RemoteServer *s, int fd) {
342         RemoteSource *source;
343
344         assert(s);
345         assert(fd >= 0 && fd < (ssize_t) s->sources_size);
346
347         source = s->sources[fd];
348         if (source) {
349                 /* this closes fd too */
350                 source_free(source);
351                 s->sources[fd] = NULL;
352                 s->active--;
353         }
354
355         return 0;
356 }
357
358 static int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
359
360         RemoteSource *source;
361         int r;
362
363         assert(s);
364         assert(fd >= 0);
365         assert(name);
366
367         if (!own_name) {
368                 name = strdup(name);
369                 if (!name)
370                         return log_oom();
371         }
372
373         r = get_source_for_fd(s, fd, name, &source);
374         if (r < 0) {
375                 log_error("Failed to create source for fd:%d (%s): %s",
376                           fd, name, strerror(-r));
377                 return r;
378         }
379
380         r = sd_event_add_io(s->events, &source->event,
381                             fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
382                             dispatch_raw_source_event, s);
383         if (r == -EPERM) {
384                 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd, name);
385                 r = sd_event_add_defer(s->events, &source->event,
386                                        dispatch_blocking_source_event, source);
387                 if (r == 0)
388                         sd_event_source_set_enabled(source->event, SD_EVENT_ON);
389         }
390         if (r < 0) {
391                 log_error("Failed to register event source for fd:%d: %s",
392                           fd, strerror(-r));
393                 goto error;
394         }
395
396         return 1; /* work to do */
397
398  error:
399         remove_source(s, fd);
400         return r;
401 }
402
403 static int add_raw_socket(RemoteServer *s, int fd) {
404         int r;
405
406         r = sd_event_add_io(s->events, &s->listen_event,
407                             fd, EPOLLIN,
408                             dispatch_raw_connection_event, s);
409         if (r < 0) {
410                 close(fd);
411                 return r;
412         }
413
414         s->active ++;
415         return 0;
416 }
417
418 static int setup_raw_socket(RemoteServer *s, const char *address) {
419         int fd;
420
421         fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
422         if (fd < 0)
423                 return fd;
424
425         return add_raw_socket(s, fd);
426 }
427
428 /**********************************************************************
429  **********************************************************************
430  **********************************************************************/
431
432 static RemoteSource *request_meta(void **connection_cls, int fd, char *hostname) {
433         RemoteSource *source;
434         Writer *writer;
435         int r;
436
437         assert(connection_cls);
438         if (*connection_cls)
439                 return *connection_cls;
440
441         r = get_writer(server, hostname, &writer);
442         if (r < 0) {
443                 log_warning("Failed to get writer for source %s: %s",
444                             hostname, strerror(-r));
445                 return NULL;
446         }
447
448         source = source_new(fd, true, hostname, writer);
449         if (!source) {
450                 log_oom();
451                 writer_unref(writer);
452                 return NULL;
453         }
454
455         log_debug("Added RemoteSource as connection metadata %p", source);
456
457         *connection_cls = source;
458         return source;
459 }
460
461 static void request_meta_free(void *cls,
462                               struct MHD_Connection *connection,
463                               void **connection_cls,
464                               enum MHD_RequestTerminationCode toe) {
465         RemoteSource *s;
466
467         assert(connection_cls);
468         s = *connection_cls;
469
470         log_debug("Cleaning up connection metadata %p", s);
471         source_free(s);
472         *connection_cls = NULL;
473 }
474
475 static int process_http_upload(
476                 struct MHD_Connection *connection,
477                 const char *upload_data,
478                 size_t *upload_data_size,
479                 RemoteSource *source) {
480
481         bool finished = false;
482         size_t remaining;
483         int r;
484
485         assert(source);
486
487         log_debug("request_handler_upload: connection %p, %zu bytes",
488                   connection, *upload_data_size);
489
490         if (*upload_data_size) {
491                 log_debug("Received %zu bytes", *upload_data_size);
492
493                 r = push_data(source, upload_data, *upload_data_size);
494                 if (r < 0)
495                         return mhd_respond_oom(connection);
496
497                 *upload_data_size = 0;
498         } else
499                 finished = true;
500
501         while (true) {
502                 r = process_source(source, arg_compress, arg_seal);
503                 if (r == -EAGAIN || r == -EWOULDBLOCK)
504                         break;
505                 else if (r < 0) {
506                         log_warning("Failed to process data for connection %p", connection);
507                         if (r == -E2BIG)
508                                 return mhd_respondf(connection,
509                                                     MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
510                                                     "Entry is too large, maximum is %u bytes.\n",
511                                                     DATA_SIZE_MAX);
512                         else
513                                 return mhd_respondf(connection,
514                                                     MHD_HTTP_UNPROCESSABLE_ENTITY,
515                                                     "Processing failed: %s.", strerror(-r));
516                 }
517         }
518
519         if (!finished)
520                 return MHD_YES;
521
522         /* The upload is finished */
523
524         remaining = source_non_empty(source);
525         if (remaining > 0) {
526                 log_warning("Premature EOFbyte. %zu bytes lost.", remaining);
527                 return mhd_respondf(connection, MHD_HTTP_EXPECTATION_FAILED,
528                                     "Premature EOF. %zu bytes of trailing data not processed.",
529                                     remaining);
530         }
531
532         return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
533 };
534
535 static int request_handler(
536                 void *cls,
537                 struct MHD_Connection *connection,
538                 const char *url,
539                 const char *method,
540                 const char *version,
541                 const char *upload_data,
542                 size_t *upload_data_size,
543                 void **connection_cls) {
544
545         const char *header;
546         int r, code, fd;
547         _cleanup_free_ char *hostname = NULL;
548
549         assert(connection);
550         assert(connection_cls);
551         assert(url);
552         assert(method);
553
554         log_debug("Handling a connection %s %s %s", method, url, version);
555
556         if (*connection_cls)
557                 return process_http_upload(connection,
558                                            upload_data, upload_data_size,
559                                            *connection_cls);
560
561         if (!streq(method, "POST"))
562                 return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
563                                    "Unsupported method.\n");
564
565         if (!streq(url, "/upload"))
566                 return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
567                                    "Not found.\n");
568
569         header = MHD_lookup_connection_value(connection,
570                                              MHD_HEADER_KIND, "Content-Type");
571         if (!header || !streq(header, "application/vnd.fdo.journal"))
572                 return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
573                                    "Content-Type: application/vnd.fdo.journal"
574                                    " is required.\n");
575
576         {
577                 const union MHD_ConnectionInfo *ci;
578
579                 ci = MHD_get_connection_info(connection,
580                                              MHD_CONNECTION_INFO_CONNECTION_FD);
581                 if (!ci) {
582                         log_error("MHD_get_connection_info failed: cannot get remote fd");
583                         return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
584                                            "Cannot check remote address");
585                 }
586
587                 fd = ci->connect_fd;
588                 assert(fd >= 0);
589         }
590
591         if (server->check_trust) {
592                 r = check_permissions(connection, &code, &hostname);
593                 if (r < 0)
594                         return code;
595         } else {
596                 r = getnameinfo_pretty(fd, &hostname);
597                 if (r < 0) {
598                         return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
599                                            "Cannot check remote hostname");
600                 }
601         }
602
603         assert(hostname);
604
605         if (!request_meta(connection_cls, fd, hostname))
606                 return respond_oom(connection);
607         hostname = NULL;
608         return MHD_YES;
609 }
610
611 static int setup_microhttpd_server(RemoteServer *s,
612                                    int fd,
613                                    const char *key,
614                                    const char *cert,
615                                    const char *trust) {
616         struct MHD_OptionItem opts[] = {
617                 { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
618                 { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
619                 { MHD_OPTION_LISTEN_SOCKET, fd},
620                 { MHD_OPTION_END},
621                 { MHD_OPTION_END},
622                 { MHD_OPTION_END},
623                 { MHD_OPTION_END}};
624         int opts_pos = 3;
625         int flags =
626                 MHD_USE_DEBUG |
627                 MHD_USE_PEDANTIC_CHECKS |
628                 MHD_USE_EPOLL_LINUX_ONLY |
629                 MHD_USE_DUAL_STACK;
630
631         const union MHD_DaemonInfo *info;
632         int r, epoll_fd;
633         MHDDaemonWrapper *d;
634
635         assert(fd >= 0);
636
637         r = fd_nonblock(fd, true);
638         if (r < 0) {
639                 log_error("Failed to make fd:%d nonblocking: %s", fd, strerror(-r));
640                 return r;
641         }
642
643         if (key) {
644                 assert(cert);
645
646                 opts[opts_pos++] = (struct MHD_OptionItem)
647                         {MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
648                 opts[opts_pos++] = (struct MHD_OptionItem)
649                         {MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
650
651                 flags |= MHD_USE_SSL;
652
653                 if (trust)
654                         opts[opts_pos++] = (struct MHD_OptionItem)
655                                 {MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
656         }
657
658         d = new(MHDDaemonWrapper, 1);
659         if (!d)
660                 return log_oom();
661
662         d->fd = (uint64_t) fd;
663
664         d->daemon = MHD_start_daemon(flags, 0,
665                                      NULL, NULL,
666                                      request_handler, NULL,
667                                      MHD_OPTION_ARRAY, opts,
668                                      MHD_OPTION_END);
669         if (!d->daemon) {
670                 log_error("Failed to start Âµhttp daemon");
671                 r = -EINVAL;
672                 goto error;
673         }
674
675         log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
676                   key ? "HTTPS" : "HTTP", fd, d);
677
678
679         info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
680         if (!info) {
681                 log_error("µhttp returned NULL daemon info");
682                 r = -ENOTSUP;
683                 goto error;
684         }
685
686         epoll_fd = info->listen_fd;
687         if (epoll_fd < 0) {
688                 log_error("µhttp epoll fd is invalid");
689                 r = -EUCLEAN;
690                 goto error;
691         }
692
693         r = sd_event_add_io(s->events, &d->event,
694                             epoll_fd, EPOLLIN,
695                             dispatch_http_event, d);
696         if (r < 0) {
697                 log_error("Failed to add event callback: %s", strerror(-r));
698                 goto error;
699         }
700
701         r = hashmap_ensure_allocated(&s->daemons, &uint64_hash_ops);
702         if (r < 0) {
703                 log_oom();
704                 goto error;
705         }
706
707         r = hashmap_put(s->daemons, &d->fd, d);
708         if (r < 0) {
709                 log_error("Failed to add daemon to hashmap: %s", strerror(-r));
710                 goto error;
711         }
712
713         s->active ++;
714         return 0;
715
716 error:
717         MHD_stop_daemon(d->daemon);
718         free(d->daemon);
719         free(d);
720         return r;
721 }
722
723 static int setup_microhttpd_socket(RemoteServer *s,
724                                    const char *address,
725                                    const char *key,
726                                    const char *cert,
727                                    const char *trust) {
728         int fd;
729
730         fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
731         if (fd < 0)
732                 return fd;
733
734         return setup_microhttpd_server(s, fd, key, cert, trust);
735 }
736
737 static int dispatch_http_event(sd_event_source *event,
738                                int fd,
739                                uint32_t revents,
740                                void *userdata) {
741         MHDDaemonWrapper *d = userdata;
742         int r;
743
744         assert(d);
745
746         r = MHD_run(d->daemon);
747         if (r == MHD_NO) {
748                 log_error("MHD_run failed!");
749                 // XXX: unregister daemon
750                 return -EINVAL;
751         }
752
753         return 1; /* work to do */
754 }
755
756 /**********************************************************************
757  **********************************************************************
758  **********************************************************************/
759
760 static int dispatch_sigterm(sd_event_source *event,
761                             const struct signalfd_siginfo *si,
762                             void *userdata) {
763         RemoteServer *s = userdata;
764
765         assert(s);
766
767         log_received_signal(LOG_INFO, si);
768
769         sd_event_exit(s->events, 0);
770         return 0;
771 }
772
773 static int setup_signals(RemoteServer *s) {
774         sigset_t mask;
775         int r;
776
777         assert(s);
778
779         assert_se(sigemptyset(&mask) == 0);
780         sigset_add_many(&mask, SIGINT, SIGTERM, -1);
781         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
782
783         r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, dispatch_sigterm, s);
784         if (r < 0)
785                 return r;
786
787         r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, dispatch_sigterm, s);
788         if (r < 0)
789                 return r;
790
791         return 0;
792 }
793
794 static int fd_fd(const char *spec) {
795         int fd, r;
796
797         r = safe_atoi(spec, &fd);
798         if (r < 0)
799                 return r;
800         if (fd < 0)
801                 return -EINVAL;
802
803         return fd;
804 }
805
806 static int remoteserver_init(RemoteServer *s,
807                              const char* key,
808                              const char* cert,
809                              const char* trust) {
810         int r, n, fd;
811         char **file;
812
813         assert(s);
814
815         if ((arg_listen_raw || arg_listen_http) && trust) {
816                 log_error("Option --trust makes all non-HTTPS connections untrusted.");
817                 return -EINVAL;
818         }
819
820         r = sd_event_default(&s->events);
821         if (r < 0) {
822                 log_error("Failed to allocate event loop: %s", strerror(-r));
823                 return r;
824         }
825
826         setup_signals(s);
827
828         assert(server == NULL);
829         server = s;
830
831         r = init_writer_hashmap(s);
832         if (r < 0)
833                 return r;
834
835         n = sd_listen_fds(true);
836         if (n < 0) {
837                 log_error("Failed to read listening file descriptors from environment: %s",
838                           strerror(-n));
839                 return n;
840         } else
841                 log_info("Received %d descriptors", n);
842
843         if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
844                 log_error("Received fewer sockets than expected");
845                 return -EBADFD;
846         }
847
848         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
849                 if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
850                         log_info("Received a listening socket (fd:%d)", fd);
851
852                         if (fd == http_socket)
853                                 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
854                         else if (fd == https_socket)
855                                 r = setup_microhttpd_server(s, fd, key, cert, trust);
856                         else
857                                 r = add_raw_socket(s, fd);
858                 } else if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
859                         char *hostname;
860
861                         r = getnameinfo_pretty(fd, &hostname);
862                         if (r < 0) {
863                                 log_error("Failed to retrieve remote name: %s", strerror(-r));
864                                 return r;
865                         }
866
867                         log_info("Received a connection socket (fd:%d) from %s", fd, hostname);
868
869                         r = add_source(s, fd, hostname, true);
870                         if (r < 0)
871                                 free(hostname);
872                 } else {
873                         log_error("Unknown socket passed on fd:%d", fd);
874
875                         return -EINVAL;
876                 }
877
878                 if(r < 0) {
879                         log_error("Failed to register socket (fd:%d): %s",
880                                   fd, strerror(-r));
881                         return r;
882                 }
883         }
884
885         if (arg_url) {
886                 const char *url, *hostname;
887
888                 url = strappenda(arg_url, "/entries");
889
890                 if (arg_getter) {
891                         log_info("Spawning getter %s...", url);
892                         fd = spawn_getter(arg_getter, url);
893                 } else {
894                         log_info("Spawning curl %s...", url);
895                         fd = spawn_curl(url);
896                 }
897                 if (fd < 0)
898                         return fd;
899
900                 hostname =
901                         startswith(arg_url, "https://") ?:
902                         startswith(arg_url, "http://") ?:
903                         arg_url;
904
905                 r = add_source(s, fd, (char*) hostname, false);
906                 if (r < 0)
907                         return r;
908         }
909
910         if (arg_listen_raw) {
911                 log_info("Listening on a socket...");
912                 r = setup_raw_socket(s, arg_listen_raw);
913                 if (r < 0)
914                         return r;
915         }
916
917         if (arg_listen_http) {
918                 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
919                 if (r < 0)
920                         return r;
921         }
922
923         if (arg_listen_https) {
924                 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
925                 if (r < 0)
926                         return r;
927         }
928
929         STRV_FOREACH(file, arg_files) {
930                 const char *output_name;
931
932                 if (streq(*file, "-")) {
933                         log_info("Using standard input as source.");
934
935                         fd = STDIN_FILENO;
936                         output_name = "stdin";
937                 } else {
938                         log_info("Reading file %s...", *file);
939
940                         fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
941                         if (fd < 0) {
942                                 log_error("Failed to open %s: %m", *file);
943                                 return -errno;
944                         }
945                         output_name = *file;
946                 }
947
948                 r = add_source(s, fd, (char*) output_name, false);
949                 if (r < 0)
950                         return r;
951         }
952
953         if (s->active == 0) {
954                 log_error("Zarro sources specified");
955                 return -EINVAL;
956         }
957
958         if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) {
959                 /* In this case we know what the writer will be
960                    called, so we can create it and verify that we can
961                    create output as expected. */
962                 r = get_writer(s, NULL, &s->_single_writer);
963                 if (r < 0)
964                         return r;
965         }
966
967         return 0;
968 }
969
970 static void server_destroy(RemoteServer *s) {
971         size_t i;
972         MHDDaemonWrapper *d;
973
974         while ((d = hashmap_steal_first(s->daemons))) {
975                 MHD_stop_daemon(d->daemon);
976                 sd_event_source_unref(d->event);
977                 free(d);
978         }
979
980         hashmap_free(s->daemons);
981
982         assert(s->sources_size == 0 || s->sources);
983         for (i = 0; i < s->sources_size; i++)
984                 remove_source(s, i);
985         free(s->sources);
986
987         writer_unref(s->_single_writer);
988         hashmap_free(s->writers);
989
990         sd_event_source_unref(s->sigterm_event);
991         sd_event_source_unref(s->sigint_event);
992         sd_event_source_unref(s->listen_event);
993         sd_event_unref(s->events);
994
995         /* fds that we're listening on remain open... */
996 }
997
998 /**********************************************************************
999  **********************************************************************
1000  **********************************************************************/
1001
1002 static int dispatch_raw_source_event(sd_event_source *event,
1003                                      int fd,
1004                                      uint32_t revents,
1005                                      void *userdata) {
1006
1007         RemoteServer *s = userdata;
1008         RemoteSource *source;
1009         int r;
1010
1011         assert(fd >= 0 && fd < (ssize_t) s->sources_size);
1012         source = s->sources[fd];
1013         assert(source->fd == fd);
1014
1015         r = process_source(source, arg_compress, arg_seal);
1016         if (source->state == STATE_EOF) {
1017                 size_t remaining;
1018
1019                 log_info("EOF reached with source fd:%d (%s)",
1020                          source->fd, source->name);
1021
1022                 remaining = source_non_empty(source);
1023                 if (remaining > 0)
1024                         log_warning("Premature EOF. %zu bytes lost.", remaining);
1025                 remove_source(s, source->fd);
1026                 log_info("%zd active sources remaining", s->active);
1027                 return 0;
1028         } else if (r == -E2BIG) {
1029                 log_error("Entry too big, skipped");
1030                 return 1;
1031         } else if (r == -EAGAIN) {
1032                 return 0;
1033         } else if (r < 0) {
1034                 log_info("Closing connection: %s", strerror(-r));
1035                 remove_source(server, fd);
1036                 return 0;
1037         } else
1038                 return 1;
1039 }
1040
1041 static int dispatch_blocking_source_event(sd_event_source *event,
1042                                           void *userdata) {
1043         RemoteSource *source = userdata;
1044
1045         return dispatch_raw_source_event(event, source->fd, EPOLLIN, server);
1046 }
1047
1048 static int accept_connection(const char* type, int fd,
1049                              SocketAddress *addr, char **hostname) {
1050         int fd2, r;
1051
1052         log_debug("Accepting new %s connection on fd:%d", type, fd);
1053         fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
1054         if (fd2 < 0) {
1055                 log_error("accept() on fd:%d failed: %m", fd);
1056                 return -errno;
1057         }
1058
1059         switch(socket_address_family(addr)) {
1060         case AF_INET:
1061         case AF_INET6: {
1062                 _cleanup_free_ char *a = NULL;
1063                 char *b;
1064
1065                 r = socket_address_print(addr, &a);
1066                 if (r < 0) {
1067                         log_error("socket_address_print(): %s", strerror(-r));
1068                         close(fd2);
1069                         return r;
1070                 }
1071
1072                 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
1073                 if (r < 0) {
1074                         close(fd2);
1075                         return r;
1076                 }
1077
1078                 log_info("Accepted %s %s connection from %s",
1079                          type,
1080                          socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
1081                          a);
1082
1083                 *hostname = b;
1084
1085                 return fd2;
1086         };
1087         default:
1088                 log_error("Rejected %s connection with unsupported family %d",
1089                           type, socket_address_family(addr));
1090                 close(fd2);
1091
1092                 return -EINVAL;
1093         }
1094 }
1095
1096 static int dispatch_raw_connection_event(sd_event_source *event,
1097                                          int fd,
1098                                          uint32_t revents,
1099                                          void *userdata) {
1100         RemoteServer *s = userdata;
1101         int fd2, r;
1102         SocketAddress addr = {
1103                 .size = sizeof(union sockaddr_union),
1104                 .type = SOCK_STREAM,
1105         };
1106         char *hostname;
1107
1108         fd2 = accept_connection("raw", fd, &addr, &hostname);
1109         if (fd2 < 0)
1110                 return fd2;
1111
1112         r = add_source(s, fd2, hostname, true);
1113         if (r < 0)
1114                 free(hostname);
1115         return r;
1116 }
1117
1118 /**********************************************************************
1119  **********************************************************************
1120  **********************************************************************/
1121
1122 static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
1123         [JOURNAL_WRITE_SPLIT_NONE] = "none",
1124         [JOURNAL_WRITE_SPLIT_HOST] = "host",
1125 };
1126
1127 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
1128 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
1129                                 journal_write_split_mode,
1130                                 JournalWriteSplitMode,
1131                                 "Failed to parse split mode setting");
1132
1133 static int parse_config(void) {
1134         const ConfigTableItem items[] = {
1135                 { "Remote",  "SplitMode",              config_parse_write_split_mode, 0, &arg_split_mode },
1136                 { "Remote",  "ServerKeyFile",          config_parse_path,             0, &arg_key        },
1137                 { "Remote",  "ServerCertificateFile",  config_parse_path,             0, &arg_cert       },
1138                 { "Remote",  "TrustedCertificateFile", config_parse_path,             0, &arg_trust      },
1139                 {}};
1140
1141         return config_parse(NULL, PKGSYSCONFDIR "/journal-remote.conf", NULL,
1142                             "Remote\0",
1143                             config_item_table_lookup, items,
1144                             false, false, true, NULL);
1145 }
1146
1147 static void help(void) {
1148         printf("%s [OPTIONS...] {FILE|-}...\n\n"
1149                "Write external journal events to journal file(s).\n\n"
1150                "  -h --help               Show this help\n"
1151                "     --version            Show package version\n"
1152                "     --url=URL            Read events from systemd-journal-gatewayd at URL\n"
1153                "     --getter=COMMAND     Read events from the output of COMMAND\n"
1154                "     --listen-raw=ADDR    Listen for connections at ADDR\n"
1155                "     --listen-http=ADDR   Listen for HTTP connections at ADDR\n"
1156                "     --listen-https=ADDR  Listen for HTTPS connections at ADDR\n"
1157                "  -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1158                "     --compress[=BOOL]    Use XZ-compression in the output journal (default: yes)\n"
1159                "     --seal[=BOOL]        Use Event sealing in the output journal (default: no)\n"
1160                "     --key=FILENAME       Specify key in PEM format (default:\n"
1161                "                          \"" PRIV_KEY_FILE "\")\n"
1162                "     --cert=FILENAME      Specify certificate in PEM format (default:\n"
1163                "                          \"" CERT_FILE "\")\n"
1164                "     --trust=FILENAME|all Specify CA certificate or disable checking (default:\n"
1165                "                          \"" TRUST_FILE "\")\n"
1166                "     --gnutls-log=CATEGORY...\n"
1167                "                          Specify a list of gnutls logging categories\n"
1168                "\n"
1169                "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1170                , program_invocation_short_name);
1171 }
1172
1173 static int parse_argv(int argc, char *argv[]) {
1174         enum {
1175                 ARG_VERSION = 0x100,
1176                 ARG_URL,
1177                 ARG_LISTEN_RAW,
1178                 ARG_LISTEN_HTTP,
1179                 ARG_LISTEN_HTTPS,
1180                 ARG_GETTER,
1181                 ARG_SPLIT_MODE,
1182                 ARG_COMPRESS,
1183                 ARG_SEAL,
1184                 ARG_KEY,
1185                 ARG_CERT,
1186                 ARG_TRUST,
1187                 ARG_GNUTLS_LOG,
1188         };
1189
1190         static const struct option options[] = {
1191                 { "help",         no_argument,       NULL, 'h'              },
1192                 { "version",      no_argument,       NULL, ARG_VERSION      },
1193                 { "url",          required_argument, NULL, ARG_URL          },
1194                 { "getter",       required_argument, NULL, ARG_GETTER       },
1195                 { "listen-raw",   required_argument, NULL, ARG_LISTEN_RAW   },
1196                 { "listen-http",  required_argument, NULL, ARG_LISTEN_HTTP  },
1197                 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1198                 { "output",       required_argument, NULL, 'o'              },
1199                 { "split-mode",   required_argument, NULL, ARG_SPLIT_MODE   },
1200                 { "compress",     optional_argument, NULL, ARG_COMPRESS     },
1201                 { "seal",         optional_argument, NULL, ARG_SEAL         },
1202                 { "key",          required_argument, NULL, ARG_KEY          },
1203                 { "cert",         required_argument, NULL, ARG_CERT         },
1204                 { "trust",        required_argument, NULL, ARG_TRUST        },
1205                 { "gnutls-log",   required_argument, NULL, ARG_GNUTLS_LOG   },
1206                 {}
1207         };
1208
1209         int c, r;
1210         bool type_a, type_b;
1211
1212         assert(argc >= 0);
1213         assert(argv);
1214
1215         while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1216                 switch(c) {
1217                 case 'h':
1218                         help();
1219                         return 0 /* done */;
1220
1221                 case ARG_VERSION:
1222                         puts(PACKAGE_STRING);
1223                         puts(SYSTEMD_FEATURES);
1224                         return 0 /* done */;
1225
1226                 case ARG_URL:
1227                         if (arg_url) {
1228                                 log_error("cannot currently set more than one --url");
1229                                 return -EINVAL;
1230                         }
1231
1232                         arg_url = optarg;
1233                         break;
1234
1235                 case ARG_GETTER:
1236                         if (arg_getter) {
1237                                 log_error("cannot currently use --getter more than once");
1238                                 return -EINVAL;
1239                         }
1240
1241                         arg_getter = optarg;
1242                         break;
1243
1244                 case ARG_LISTEN_RAW:
1245                         if (arg_listen_raw) {
1246                                 log_error("cannot currently use --listen-raw more than once");
1247                                 return -EINVAL;
1248                         }
1249
1250                         arg_listen_raw = optarg;
1251                         break;
1252
1253                 case ARG_LISTEN_HTTP:
1254                         if (arg_listen_http || http_socket >= 0) {
1255                                 log_error("cannot currently use --listen-http more than once");
1256                                 return -EINVAL;
1257                         }
1258
1259                         r = fd_fd(optarg);
1260                         if (r >= 0)
1261                                 http_socket = r;
1262                         else
1263                                 arg_listen_http = optarg;
1264                         break;
1265
1266                 case ARG_LISTEN_HTTPS:
1267                         if (arg_listen_https || https_socket >= 0) {
1268                                 log_error("cannot currently use --listen-https more than once");
1269                                 return -EINVAL;
1270                         }
1271
1272                         r = fd_fd(optarg);
1273                         if (r >= 0)
1274                                 https_socket = r;
1275                         else
1276                                 arg_listen_https = optarg;
1277
1278                         break;
1279
1280                 case ARG_KEY:
1281                         if (arg_key) {
1282                                 log_error("Key file specified twice");
1283                                 return -EINVAL;
1284                         }
1285
1286                         arg_key = strdup(optarg);
1287                         if (!arg_key)
1288                                 return log_oom();
1289
1290                         break;
1291
1292                 case ARG_CERT:
1293                         if (arg_cert) {
1294                                 log_error("Certificate file specified twice");
1295                                 return -EINVAL;
1296                         }
1297
1298                         arg_cert = strdup(optarg);
1299                         if (!arg_cert)
1300                                 return log_oom();
1301
1302                         break;
1303
1304                 case ARG_TRUST:
1305                         if (arg_trust || arg_trust_all) {
1306                                 log_error("Confusing trusted CA configuration");
1307                                 return -EINVAL;
1308                         }
1309
1310                         if (streq(optarg, "all"))
1311                                 arg_trust_all = true;
1312                         else {
1313 #ifdef HAVE_GNUTLS
1314                                 arg_trust = strdup(optarg);
1315                                 if (!arg_trust)
1316                                         return log_oom();
1317 #else
1318                                 log_error("Option --trust is not available.");
1319                                 return -EINVAL;
1320 #endif
1321                         }
1322
1323                         break;
1324
1325                 case 'o':
1326                         if (arg_output) {
1327                                 log_error("cannot use --output/-o more than once");
1328                                 return -EINVAL;
1329                         }
1330
1331                         arg_output = optarg;
1332                         break;
1333
1334                 case ARG_SPLIT_MODE:
1335                         arg_split_mode = journal_write_split_mode_from_string(optarg);
1336                         if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) {
1337                                 log_error("Invalid split mode: %s", optarg);
1338                                 return -EINVAL;
1339                         }
1340                         break;
1341
1342                 case ARG_COMPRESS:
1343                         if (optarg) {
1344                                 r = parse_boolean(optarg);
1345                                 if (r < 0) {
1346                                         log_error("Failed to parse --compress= parameter.");
1347                                         return -EINVAL;
1348                                 }
1349
1350                                 arg_compress = !!r;
1351                         } else
1352                                 arg_compress = true;
1353
1354                         break;
1355
1356                 case ARG_SEAL:
1357                         if (optarg) {
1358                                 r = parse_boolean(optarg);
1359                                 if (r < 0) {
1360                                         log_error("Failed to parse --seal= parameter.");
1361                                         return -EINVAL;
1362                                 }
1363
1364                                 arg_seal = !!r;
1365                         } else
1366                                 arg_seal = true;
1367
1368                         break;
1369
1370                 case ARG_GNUTLS_LOG: {
1371 #ifdef HAVE_GNUTLS
1372                         const char *word, *state;
1373                         size_t size;
1374
1375                         FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
1376                                 char *cat;
1377
1378                                 cat = strndup(word, size);
1379                                 if (!cat)
1380                                         return log_oom();
1381
1382                                 if (strv_consume(&arg_gnutls_log, cat) < 0)
1383                                         return log_oom();
1384                         }
1385                         break;
1386 #else
1387                         log_error("Option --gnutls-log is not available.");
1388                         return -EINVAL;
1389 #endif
1390                 }
1391
1392                 case '?':
1393                         return -EINVAL;
1394
1395                 default:
1396                         assert_not_reached("Unknown option code.");
1397                 }
1398
1399         if (optind < argc)
1400                 arg_files = argv + optind;
1401
1402         type_a = arg_getter || !strv_isempty(arg_files);
1403         type_b = arg_url
1404                 || arg_listen_raw
1405                 || arg_listen_http || arg_listen_https
1406                 || sd_listen_fds(false) > 0;
1407         if (type_a && type_b) {
1408                 log_error("Cannot use file input or --getter with "
1409                           "--arg-listen-... or socket activation.");
1410                 return -EINVAL;
1411         }
1412         if (type_a) {
1413                 if (!arg_output) {
1414                         log_error("Option --output must be specified with file input or --getter.");
1415                         return -EINVAL;
1416                 }
1417
1418                 arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
1419         }
1420
1421         if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE
1422             && arg_output && is_dir(arg_output, true) > 0) {
1423                 log_error("For SplitMode=none, output must be a file.");
1424                 return -EINVAL;
1425         }
1426
1427         if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
1428             && arg_output && is_dir(arg_output, true) <= 0) {
1429                 log_error("For SplitMode=host, output must be a directory.");
1430                 return -EINVAL;
1431         }
1432
1433         log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1434                   journal_write_split_mode_to_string(arg_split_mode),
1435                   strna(arg_key),
1436                   strna(arg_cert),
1437                   strna(arg_trust));
1438
1439         return 1 /* work to do */;
1440 }
1441
1442 static int load_certificates(char **key, char **cert, char **trust) {
1443         int r;
1444
1445         r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
1446         if (r < 0) {
1447                 log_error("Failed to read key from file '%s': %s",
1448                           arg_key ?: PRIV_KEY_FILE, strerror(-r));
1449                 return r;
1450         }
1451
1452         r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1453         if (r < 0) {
1454                 log_error("Failed to read certificate from file '%s': %s",
1455                           arg_cert ?: CERT_FILE, strerror(-r));
1456                 return r;
1457         }
1458
1459         if (arg_trust_all)
1460                 log_info("Certificate checking disabled.");
1461         else {
1462                 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1463                 if (r < 0) {
1464                         log_error("Failed to read CA certificate file '%s': %s",
1465                                   arg_trust ?: TRUST_FILE, strerror(-r));
1466                         return r;
1467                 }
1468         }
1469
1470         return 0;
1471 }
1472
1473 static int setup_gnutls_logger(char **categories) {
1474         if (!arg_listen_http && !arg_listen_https)
1475                 return 0;
1476
1477 #ifdef HAVE_GNUTLS
1478         {
1479                 char **cat;
1480                 int r;
1481
1482                 gnutls_global_set_log_function(log_func_gnutls);
1483
1484                 if (categories)
1485                         STRV_FOREACH(cat, categories) {
1486                                 r = log_enable_gnutls_category(*cat);
1487                                 if (r < 0)
1488                                         return r;
1489                         }
1490                 else
1491                         log_reset_gnutls_level();
1492         }
1493 #endif
1494
1495         return 0;
1496 }
1497
1498 int main(int argc, char **argv) {
1499         RemoteServer s = {};
1500         int r;
1501         _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1502
1503         log_show_color(true);
1504         log_parse_environment();
1505
1506         r = parse_config();
1507         if (r < 0)
1508                 return EXIT_FAILURE;
1509
1510         r = parse_argv(argc, argv);
1511         if (r <= 0)
1512                 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1513
1514         r = setup_gnutls_logger(arg_gnutls_log);
1515         if (r < 0)
1516                 return EXIT_FAILURE;
1517
1518         if (arg_listen_https || https_socket >= 0)
1519                 if (load_certificates(&key, &cert, &trust) < 0)
1520                         return EXIT_FAILURE;
1521
1522         if (remoteserver_init(&s, key, cert, trust) < 0)
1523                 return EXIT_FAILURE;
1524
1525         sd_event_set_watchdog(s.events, true);
1526
1527         log_debug("%s running as pid "PID_FMT,
1528                   program_invocation_short_name, getpid());
1529         sd_notify(false,
1530                   "READY=1\n"
1531                   "STATUS=Processing requests...");
1532
1533         while (s.active) {
1534                 r = sd_event_get_state(s.events);
1535                 if (r < 0)
1536                         break;
1537                 if (r == SD_EVENT_FINISHED)
1538                         break;
1539
1540                 r = sd_event_run(s.events, -1);
1541                 if (r < 0) {
1542                         log_error("Failed to run event loop: %s", strerror(-r));
1543                         break;
1544                 }
1545         }
1546
1547         sd_notifyf(false,
1548                    "STOPPING=1\n"
1549                    "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
1550         log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
1551
1552         server_destroy(&s);
1553
1554         free(arg_key);
1555         free(arg_cert);
1556         free(arg_trust);
1557
1558         return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1559 }