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