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