chiark / gitweb /
treewide: auto-convert the simple cases to log_*_errno()
[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("Failed to open output journal %s: %s",
214                           output, strerror(-r));
215         else
216                 log_info("Opened output file %s", w->journal->path);
217         return r;
218 }
219
220 /**********************************************************************
221  **********************************************************************
222  **********************************************************************/
223
224 static int init_writer_hashmap(RemoteServer *s) {
225         static const struct hash_ops *hash_ops[] = {
226                 [JOURNAL_WRITE_SPLIT_NONE] = NULL,
227                 [JOURNAL_WRITE_SPLIT_HOST] = &string_hash_ops,
228         };
229
230         assert(arg_split_mode >= 0 && arg_split_mode < (int) ELEMENTSOF(hash_ops));
231
232         s->writers = hashmap_new(hash_ops[arg_split_mode]);
233         if (!s->writers)
234                 return log_oom();
235
236         return 0;
237 }
238
239 static int get_writer(RemoteServer *s, const char *host,
240                       Writer **writer) {
241         const void *key;
242         _cleanup_writer_unref_ Writer *w = NULL;
243         int r;
244
245         switch(arg_split_mode) {
246         case JOURNAL_WRITE_SPLIT_NONE:
247                 key = "one and only";
248                 break;
249
250         case JOURNAL_WRITE_SPLIT_HOST:
251                 assert(host);
252                 key = host;
253                 break;
254
255         default:
256                 assert_not_reached("what split mode?");
257         }
258
259         w = hashmap_get(s->writers, key);
260         if (w)
261                 writer_ref(w);
262         else {
263                 w = writer_new(s);
264                 if (!w)
265                         return log_oom();
266
267                 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST) {
268                         w->hashmap_key = strdup(key);
269                         if (!w->hashmap_key)
270                                 return log_oom();
271                 }
272
273                 r = open_output(w, host);
274                 if (r < 0)
275                         return r;
276
277                 r = hashmap_put(s->writers, w->hashmap_key ?: key, w);
278                 if (r < 0)
279                         return r;
280         }
281
282         *writer = w;
283         w = NULL;
284         return 0;
285 }
286
287 /**********************************************************************
288  **********************************************************************
289  **********************************************************************/
290
291 /* This should go away as soon as Âµhttpd allows state to be passed around. */
292 static RemoteServer *server;
293
294 static int dispatch_raw_source_event(sd_event_source *event,
295                                      int fd,
296                                      uint32_t revents,
297                                      void *userdata);
298 static int dispatch_blocking_source_event(sd_event_source *event,
299                                           void *userdata);
300 static int dispatch_raw_connection_event(sd_event_source *event,
301                                          int fd,
302                                          uint32_t revents,
303                                          void *userdata);
304 static int dispatch_http_event(sd_event_source *event,
305                                int fd,
306                                uint32_t revents,
307                                void *userdata);
308
309 static int get_source_for_fd(RemoteServer *s,
310                              int fd, char *name, RemoteSource **source) {
311         Writer *writer;
312         int r;
313
314         /* This takes ownership of name, but only on success. */
315
316         assert(fd >= 0);
317         assert(source);
318
319         if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
320                 return log_oom();
321
322         r = get_writer(s, name, &writer);
323         if (r < 0) {
324                 log_warning("Failed to get writer for source %s: %s",
325                             name, strerror(-r));
326                 return r;
327         }
328
329         if (s->sources[fd] == NULL) {
330                 s->sources[fd] = source_new(fd, false, name, writer);
331                 if (!s->sources[fd]) {
332                         writer_unref(writer);
333                         return log_oom();
334                 }
335
336                 s->active++;
337         }
338
339         *source = s->sources[fd];
340         return 0;
341 }
342
343 static int remove_source(RemoteServer *s, int fd) {
344         RemoteSource *source;
345
346         assert(s);
347         assert(fd >= 0 && fd < (ssize_t) s->sources_size);
348
349         source = s->sources[fd];
350         if (source) {
351                 /* this closes fd too */
352                 source_free(source);
353                 s->sources[fd] = NULL;
354                 s->active--;
355         }
356
357         return 0;
358 }
359
360 static int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
361
362         RemoteSource *source;
363         int r;
364
365         /* This takes ownership of name, even on failure, if own_name is true. */
366
367         assert(s);
368         assert(fd >= 0);
369         assert(name);
370
371         if (!own_name) {
372                 name = strdup(name);
373                 if (!name)
374                         return log_oom();
375         }
376
377         r = get_source_for_fd(s, fd, name, &source);
378         if (r < 0) {
379                 log_error("Failed to create source for fd:%d (%s): %s",
380                           fd, name, strerror(-r));
381                 free(name);
382                 return r;
383         }
384
385         r = sd_event_add_io(s->events, &source->event,
386                             fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
387                             dispatch_raw_source_event, s);
388         if (r == -EPERM) {
389                 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd, name);
390                 r = sd_event_add_defer(s->events, &source->event,
391                                        dispatch_blocking_source_event, source);
392                 if (r == 0)
393                         sd_event_source_set_enabled(source->event, SD_EVENT_ON);
394         }
395         if (r < 0) {
396                 log_error("Failed to register event source for fd:%d: %s",
397                           fd, strerror(-r));
398                 goto error;
399         }
400
401         r = sd_event_source_set_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("Failed to get writer for source %s: %s",
464                             hostname, strerror(-r));
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("Failed to read listening file descriptors from environment: %s",
860                           strerror(-n));
861                 return n;
862         } else
863                 log_info("Received %d descriptors", n);
864
865         if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
866                 log_error("Received fewer sockets than expected");
867                 return -EBADFD;
868         }
869
870         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
871                 if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
872                         log_info("Received a listening socket (fd:%d)", fd);
873
874                         if (fd == http_socket)
875                                 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
876                         else if (fd == https_socket)
877                                 r = setup_microhttpd_server(s, fd, key, cert, trust);
878                         else
879                                 r = add_raw_socket(s, fd);
880                 } else if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
881                         char *hostname;
882
883                         r = getnameinfo_pretty(fd, &hostname);
884                         if (r < 0) {
885                                 log_error_errno(-r, "Failed to retrieve remote name: %m");
886                                 return r;
887                         }
888
889                         log_info("Received a connection socket (fd:%d) from %s", fd, hostname);
890
891                         r = add_source(s, fd, hostname, true);
892                 } else {
893                         log_error("Unknown socket passed on fd:%d", fd);
894
895                         return -EINVAL;
896                 }
897
898                 if(r < 0) {
899                         log_error("Failed to register socket (fd:%d): %s",
900                                   fd, strerror(-r));
901                         return r;
902                 }
903         }
904
905         if (arg_url) {
906                 const char *url, *hostname;
907
908                 url = strappenda(arg_url, "/entries");
909
910                 if (arg_getter) {
911                         log_info("Spawning getter %s...", url);
912                         fd = spawn_getter(arg_getter, url);
913                 } else {
914                         log_info("Spawning curl %s...", url);
915                         fd = spawn_curl(url);
916                 }
917                 if (fd < 0)
918                         return fd;
919
920                 hostname =
921                         startswith(arg_url, "https://") ?:
922                         startswith(arg_url, "http://") ?:
923                         arg_url;
924
925                 r = add_source(s, fd, (char*) hostname, false);
926                 if (r < 0)
927                         return r;
928         }
929
930         if (arg_listen_raw) {
931                 log_info("Listening on a socket...");
932                 r = setup_raw_socket(s, arg_listen_raw);
933                 if (r < 0)
934                         return r;
935         }
936
937         if (arg_listen_http) {
938                 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
939                 if (r < 0)
940                         return r;
941         }
942
943         if (arg_listen_https) {
944                 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
945                 if (r < 0)
946                         return r;
947         }
948
949         STRV_FOREACH(file, arg_files) {
950                 const char *output_name;
951
952                 if (streq(*file, "-")) {
953                         log_info("Using standard input as source.");
954
955                         fd = STDIN_FILENO;
956                         output_name = "stdin";
957                 } else {
958                         log_info("Reading file %s...", *file);
959
960                         fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
961                         if (fd < 0) {
962                                 log_error("Failed to open %s: %m", *file);
963                                 return -errno;
964                         }
965                         output_name = *file;
966                 }
967
968                 r = add_source(s, fd, (char*) output_name, false);
969                 if (r < 0)
970                         return r;
971         }
972
973         if (s->active == 0) {
974                 log_error("Zarro sources specified");
975                 return -EINVAL;
976         }
977
978         if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) {
979                 /* In this case we know what the writer will be
980                    called, so we can create it and verify that we can
981                    create output as expected. */
982                 r = get_writer(s, NULL, &s->_single_writer);
983                 if (r < 0)
984                         return r;
985         }
986
987         return 0;
988 }
989
990 static void server_destroy(RemoteServer *s) {
991         size_t i;
992         MHDDaemonWrapper *d;
993
994         while ((d = hashmap_steal_first(s->daemons))) {
995                 MHD_stop_daemon(d->daemon);
996                 sd_event_source_unref(d->event);
997                 free(d);
998         }
999
1000         hashmap_free(s->daemons);
1001
1002         assert(s->sources_size == 0 || s->sources);
1003         for (i = 0; i < s->sources_size; i++)
1004                 remove_source(s, i);
1005         free(s->sources);
1006
1007         writer_unref(s->_single_writer);
1008         hashmap_free(s->writers);
1009
1010         sd_event_source_unref(s->sigterm_event);
1011         sd_event_source_unref(s->sigint_event);
1012         sd_event_source_unref(s->listen_event);
1013         sd_event_unref(s->events);
1014
1015         /* fds that we're listening on remain open... */
1016 }
1017
1018 /**********************************************************************
1019  **********************************************************************
1020  **********************************************************************/
1021
1022 static int dispatch_raw_source_event(sd_event_source *event,
1023                                      int fd,
1024                                      uint32_t revents,
1025                                      void *userdata) {
1026
1027         RemoteServer *s = userdata;
1028         RemoteSource *source;
1029         int r;
1030
1031         assert(fd >= 0 && fd < (ssize_t) s->sources_size);
1032         source = s->sources[fd];
1033         assert(source->fd == fd);
1034
1035         r = process_source(source, arg_compress, arg_seal);
1036         if (source->state == STATE_EOF) {
1037                 size_t remaining;
1038
1039                 log_info("EOF reached with source fd:%d (%s)",
1040                          source->fd, source->name);
1041
1042                 remaining = source_non_empty(source);
1043                 if (remaining > 0)
1044                         log_warning("Premature EOF. %zu bytes lost.", remaining);
1045                 remove_source(s, source->fd);
1046                 log_info("%zd active sources remaining", s->active);
1047                 return 0;
1048         } else if (r == -E2BIG) {
1049                 log_error("Entry too big, skipped");
1050                 return 1;
1051         } else if (r == -EAGAIN) {
1052                 return 0;
1053         } else if (r < 0) {
1054                 log_info_errno(-r, "Closing connection: %m");
1055                 remove_source(server, fd);
1056                 return 0;
1057         } else
1058                 return 1;
1059 }
1060
1061 static int dispatch_blocking_source_event(sd_event_source *event,
1062                                           void *userdata) {
1063         RemoteSource *source = userdata;
1064
1065         return dispatch_raw_source_event(event, source->fd, EPOLLIN, server);
1066 }
1067
1068 static int accept_connection(const char* type, int fd,
1069                              SocketAddress *addr, char **hostname) {
1070         int fd2, r;
1071
1072         log_debug("Accepting new %s connection on fd:%d", type, fd);
1073         fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
1074         if (fd2 < 0) {
1075                 log_error("accept() on fd:%d failed: %m", fd);
1076                 return -errno;
1077         }
1078
1079         switch(socket_address_family(addr)) {
1080         case AF_INET:
1081         case AF_INET6: {
1082                 _cleanup_free_ char *a = NULL;
1083                 char *b;
1084
1085                 r = socket_address_print(addr, &a);
1086                 if (r < 0) {
1087                         log_error_errno(-r, "socket_address_print(): %m");
1088                         close(fd2);
1089                         return r;
1090                 }
1091
1092                 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
1093                 if (r < 0) {
1094                         close(fd2);
1095                         return r;
1096                 }
1097
1098                 log_info("Accepted %s %s connection from %s",
1099                          type,
1100                          socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
1101                          a);
1102
1103                 *hostname = b;
1104
1105                 return fd2;
1106         };
1107         default:
1108                 log_error("Rejected %s connection with unsupported family %d",
1109                           type, socket_address_family(addr));
1110                 close(fd2);
1111
1112                 return -EINVAL;
1113         }
1114 }
1115
1116 static int dispatch_raw_connection_event(sd_event_source *event,
1117                                          int fd,
1118                                          uint32_t revents,
1119                                          void *userdata) {
1120         RemoteServer *s = userdata;
1121         int fd2;
1122         SocketAddress addr = {
1123                 .size = sizeof(union sockaddr_union),
1124                 .type = SOCK_STREAM,
1125         };
1126         char *hostname;
1127
1128         fd2 = accept_connection("raw", fd, &addr, &hostname);
1129         if (fd2 < 0)
1130                 return fd2;
1131
1132         return add_source(s, fd2, hostname, true);
1133 }
1134
1135 /**********************************************************************
1136  **********************************************************************
1137  **********************************************************************/
1138
1139 static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
1140         [JOURNAL_WRITE_SPLIT_NONE] = "none",
1141         [JOURNAL_WRITE_SPLIT_HOST] = "host",
1142 };
1143
1144 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
1145 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
1146                                 journal_write_split_mode,
1147                                 JournalWriteSplitMode,
1148                                 "Failed to parse split mode setting");
1149
1150 static int parse_config(void) {
1151         const ConfigTableItem items[] = {
1152                 { "Remote",  "SplitMode",              config_parse_write_split_mode, 0, &arg_split_mode },
1153                 { "Remote",  "ServerKeyFile",          config_parse_path,             0, &arg_key        },
1154                 { "Remote",  "ServerCertificateFile",  config_parse_path,             0, &arg_cert       },
1155                 { "Remote",  "TrustedCertificateFile", config_parse_path,             0, &arg_trust      },
1156                 {}};
1157
1158         return config_parse(NULL, PKGSYSCONFDIR "/journal-remote.conf", NULL,
1159                             "Remote\0",
1160                             config_item_table_lookup, items,
1161                             false, false, true, NULL);
1162 }
1163
1164 static void help(void) {
1165         printf("%s [OPTIONS...] {FILE|-}...\n\n"
1166                "Write external journal events to journal file(s).\n\n"
1167                "  -h --help                 Show this help\n"
1168                "     --version              Show package version\n"
1169                "     --url=URL              Read events from systemd-journal-gatewayd at URL\n"
1170                "     --getter=COMMAND       Read events from the output of COMMAND\n"
1171                "     --listen-raw=ADDR      Listen for connections at ADDR\n"
1172                "     --listen-http=ADDR     Listen for HTTP connections at ADDR\n"
1173                "     --listen-https=ADDR    Listen for HTTPS connections at ADDR\n"
1174                "  -o --output=FILE|DIR      Write output to FILE or DIR/external-*.journal\n"
1175                "     --compress[=BOOL]      XZ-compress the output journal (default: yes)\n"
1176                "     --seal[=BOOL]          Use event sealing (default: no)\n"
1177                "     --key=FILENAME         SSL key in PEM format (default:\n"
1178                "                            \"" PRIV_KEY_FILE "\")\n"
1179                "     --cert=FILENAME        SSL certificate in PEM format (default:\n"
1180                "                            \"" CERT_FILE "\")\n"
1181                "     --trust=FILENAME|all   SSL CA certificate or disable checking (default:\n"
1182                "                            \"" TRUST_FILE "\")\n"
1183                "     --gnutls-log=CATEGORY...\n"
1184                "                            Specify a list of gnutls logging categories\n"
1185                "     --split-mode=none|host How many output files to create\n"
1186                "\n"
1187                "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1188                , program_invocation_short_name);
1189 }
1190
1191 static int parse_argv(int argc, char *argv[]) {
1192         enum {
1193                 ARG_VERSION = 0x100,
1194                 ARG_URL,
1195                 ARG_LISTEN_RAW,
1196                 ARG_LISTEN_HTTP,
1197                 ARG_LISTEN_HTTPS,
1198                 ARG_GETTER,
1199                 ARG_SPLIT_MODE,
1200                 ARG_COMPRESS,
1201                 ARG_SEAL,
1202                 ARG_KEY,
1203                 ARG_CERT,
1204                 ARG_TRUST,
1205                 ARG_GNUTLS_LOG,
1206         };
1207
1208         static const struct option options[] = {
1209                 { "help",         no_argument,       NULL, 'h'              },
1210                 { "version",      no_argument,       NULL, ARG_VERSION      },
1211                 { "url",          required_argument, NULL, ARG_URL          },
1212                 { "getter",       required_argument, NULL, ARG_GETTER       },
1213                 { "listen-raw",   required_argument, NULL, ARG_LISTEN_RAW   },
1214                 { "listen-http",  required_argument, NULL, ARG_LISTEN_HTTP  },
1215                 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1216                 { "output",       required_argument, NULL, 'o'              },
1217                 { "split-mode",   required_argument, NULL, ARG_SPLIT_MODE   },
1218                 { "compress",     optional_argument, NULL, ARG_COMPRESS     },
1219                 { "seal",         optional_argument, NULL, ARG_SEAL         },
1220                 { "key",          required_argument, NULL, ARG_KEY          },
1221                 { "cert",         required_argument, NULL, ARG_CERT         },
1222                 { "trust",        required_argument, NULL, ARG_TRUST        },
1223                 { "gnutls-log",   required_argument, NULL, ARG_GNUTLS_LOG   },
1224                 {}
1225         };
1226
1227         int c, r;
1228         bool type_a, type_b;
1229
1230         assert(argc >= 0);
1231         assert(argv);
1232
1233         while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1234                 switch(c) {
1235                 case 'h':
1236                         help();
1237                         return 0 /* done */;
1238
1239                 case ARG_VERSION:
1240                         puts(PACKAGE_STRING);
1241                         puts(SYSTEMD_FEATURES);
1242                         return 0 /* done */;
1243
1244                 case ARG_URL:
1245                         if (arg_url) {
1246                                 log_error("cannot currently set more than one --url");
1247                                 return -EINVAL;
1248                         }
1249
1250                         arg_url = optarg;
1251                         break;
1252
1253                 case ARG_GETTER:
1254                         if (arg_getter) {
1255                                 log_error("cannot currently use --getter more than once");
1256                                 return -EINVAL;
1257                         }
1258
1259                         arg_getter = optarg;
1260                         break;
1261
1262                 case ARG_LISTEN_RAW:
1263                         if (arg_listen_raw) {
1264                                 log_error("cannot currently use --listen-raw more than once");
1265                                 return -EINVAL;
1266                         }
1267
1268                         arg_listen_raw = optarg;
1269                         break;
1270
1271                 case ARG_LISTEN_HTTP:
1272                         if (arg_listen_http || http_socket >= 0) {
1273                                 log_error("cannot currently use --listen-http more than once");
1274                                 return -EINVAL;
1275                         }
1276
1277                         r = negative_fd(optarg);
1278                         if (r >= 0)
1279                                 http_socket = r;
1280                         else
1281                                 arg_listen_http = optarg;
1282                         break;
1283
1284                 case ARG_LISTEN_HTTPS:
1285                         if (arg_listen_https || https_socket >= 0) {
1286                                 log_error("cannot currently use --listen-https more than once");
1287                                 return -EINVAL;
1288                         }
1289
1290                         r = negative_fd(optarg);
1291                         if (r >= 0)
1292                                 https_socket = r;
1293                         else
1294                                 arg_listen_https = optarg;
1295
1296                         break;
1297
1298                 case ARG_KEY:
1299                         if (arg_key) {
1300                                 log_error("Key file specified twice");
1301                                 return -EINVAL;
1302                         }
1303
1304                         arg_key = strdup(optarg);
1305                         if (!arg_key)
1306                                 return log_oom();
1307
1308                         break;
1309
1310                 case ARG_CERT:
1311                         if (arg_cert) {
1312                                 log_error("Certificate file specified twice");
1313                                 return -EINVAL;
1314                         }
1315
1316                         arg_cert = strdup(optarg);
1317                         if (!arg_cert)
1318                                 return log_oom();
1319
1320                         break;
1321
1322                 case ARG_TRUST:
1323                         if (arg_trust || arg_trust_all) {
1324                                 log_error("Confusing trusted CA configuration");
1325                                 return -EINVAL;
1326                         }
1327
1328                         if (streq(optarg, "all"))
1329                                 arg_trust_all = true;
1330                         else {
1331 #ifdef HAVE_GNUTLS
1332                                 arg_trust = strdup(optarg);
1333                                 if (!arg_trust)
1334                                         return log_oom();
1335 #else
1336                                 log_error("Option --trust is not available.");
1337                                 return -EINVAL;
1338 #endif
1339                         }
1340
1341                         break;
1342
1343                 case 'o':
1344                         if (arg_output) {
1345                                 log_error("cannot use --output/-o more than once");
1346                                 return -EINVAL;
1347                         }
1348
1349                         arg_output = optarg;
1350                         break;
1351
1352                 case ARG_SPLIT_MODE:
1353                         arg_split_mode = journal_write_split_mode_from_string(optarg);
1354                         if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) {
1355                                 log_error("Invalid split mode: %s", optarg);
1356                                 return -EINVAL;
1357                         }
1358                         break;
1359
1360                 case ARG_COMPRESS:
1361                         if (optarg) {
1362                                 r = parse_boolean(optarg);
1363                                 if (r < 0) {
1364                                         log_error("Failed to parse --compress= parameter.");
1365                                         return -EINVAL;
1366                                 }
1367
1368                                 arg_compress = !!r;
1369                         } else
1370                                 arg_compress = true;
1371
1372                         break;
1373
1374                 case ARG_SEAL:
1375                         if (optarg) {
1376                                 r = parse_boolean(optarg);
1377                                 if (r < 0) {
1378                                         log_error("Failed to parse --seal= parameter.");
1379                                         return -EINVAL;
1380                                 }
1381
1382                                 arg_seal = !!r;
1383                         } else
1384                                 arg_seal = true;
1385
1386                         break;
1387
1388                 case ARG_GNUTLS_LOG: {
1389 #ifdef HAVE_GNUTLS
1390                         const char *word, *state;
1391                         size_t size;
1392
1393                         FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
1394                                 char *cat;
1395
1396                                 cat = strndup(word, size);
1397                                 if (!cat)
1398                                         return log_oom();
1399
1400                                 if (strv_consume(&arg_gnutls_log, cat) < 0)
1401                                         return log_oom();
1402                         }
1403                         break;
1404 #else
1405                         log_error("Option --gnutls-log is not available.");
1406                         return -EINVAL;
1407 #endif
1408                 }
1409
1410                 case '?':
1411                         return -EINVAL;
1412
1413                 default:
1414                         assert_not_reached("Unknown option code.");
1415                 }
1416
1417         if (optind < argc)
1418                 arg_files = argv + optind;
1419
1420         type_a = arg_getter || !strv_isempty(arg_files);
1421         type_b = arg_url
1422                 || arg_listen_raw
1423                 || arg_listen_http || arg_listen_https
1424                 || sd_listen_fds(false) > 0;
1425         if (type_a && type_b) {
1426                 log_error("Cannot use file input or --getter with "
1427                           "--arg-listen-... or socket activation.");
1428                 return -EINVAL;
1429         }
1430         if (type_a) {
1431                 if (!arg_output) {
1432                         log_error("Option --output must be specified with file input or --getter.");
1433                         return -EINVAL;
1434                 }
1435
1436                 arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
1437         }
1438
1439         if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE
1440             && arg_output && is_dir(arg_output, true) > 0) {
1441                 log_error("For SplitMode=none, output must be a file.");
1442                 return -EINVAL;
1443         }
1444
1445         if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
1446             && arg_output && is_dir(arg_output, true) <= 0) {
1447                 log_error("For SplitMode=host, output must be a directory.");
1448                 return -EINVAL;
1449         }
1450
1451         log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1452                   journal_write_split_mode_to_string(arg_split_mode),
1453                   strna(arg_key),
1454                   strna(arg_cert),
1455                   strna(arg_trust));
1456
1457         return 1 /* work to do */;
1458 }
1459
1460 static int load_certificates(char **key, char **cert, char **trust) {
1461         int r;
1462
1463         r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
1464         if (r < 0) {
1465                 log_error("Failed to read key from file '%s': %s",
1466                           arg_key ?: PRIV_KEY_FILE, strerror(-r));
1467                 return r;
1468         }
1469
1470         r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1471         if (r < 0) {
1472                 log_error("Failed to read certificate from file '%s': %s",
1473                           arg_cert ?: CERT_FILE, strerror(-r));
1474                 return r;
1475         }
1476
1477         if (arg_trust_all)
1478                 log_info("Certificate checking disabled.");
1479         else {
1480                 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1481                 if (r < 0) {
1482                         log_error("Failed to read CA certificate file '%s': %s",
1483                                   arg_trust ?: TRUST_FILE, strerror(-r));
1484                         return r;
1485                 }
1486         }
1487
1488         return 0;
1489 }
1490
1491 static int setup_gnutls_logger(char **categories) {
1492         if (!arg_listen_http && !arg_listen_https)
1493                 return 0;
1494
1495 #ifdef HAVE_GNUTLS
1496         {
1497                 char **cat;
1498                 int r;
1499
1500                 gnutls_global_set_log_function(log_func_gnutls);
1501
1502                 if (categories)
1503                         STRV_FOREACH(cat, categories) {
1504                                 r = log_enable_gnutls_category(*cat);
1505                                 if (r < 0)
1506                                         return r;
1507                         }
1508                 else
1509                         log_reset_gnutls_level();
1510         }
1511 #endif
1512
1513         return 0;
1514 }
1515
1516 int main(int argc, char **argv) {
1517         RemoteServer s = {};
1518         int r;
1519         _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1520
1521         log_show_color(true);
1522         log_parse_environment();
1523
1524         r = parse_config();
1525         if (r < 0)
1526                 return EXIT_FAILURE;
1527
1528         r = parse_argv(argc, argv);
1529         if (r <= 0)
1530                 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1531
1532         r = setup_gnutls_logger(arg_gnutls_log);
1533         if (r < 0)
1534                 return EXIT_FAILURE;
1535
1536         if (arg_listen_https || https_socket >= 0)
1537                 if (load_certificates(&key, &cert, &trust) < 0)
1538                         return EXIT_FAILURE;
1539
1540         if (remoteserver_init(&s, key, cert, trust) < 0)
1541                 return EXIT_FAILURE;
1542
1543         r = sd_event_set_watchdog(s.events, true);
1544         if (r < 0)
1545                 log_error_errno(-r, "Failed to enable watchdog: %m");
1546         else
1547                 log_debug("Watchdog is %s.", r > 0 ? "enabled" : "disabled");
1548
1549         log_debug("%s running as pid "PID_FMT,
1550                   program_invocation_short_name, getpid());
1551         sd_notify(false,
1552                   "READY=1\n"
1553                   "STATUS=Processing requests...");
1554
1555         while (s.active) {
1556                 r = sd_event_get_state(s.events);
1557                 if (r < 0)
1558                         break;
1559                 if (r == SD_EVENT_FINISHED)
1560                         break;
1561
1562                 r = sd_event_run(s.events, -1);
1563                 if (r < 0) {
1564                         log_error_errno(-r, "Failed to run event loop: %m");
1565                         break;
1566                 }
1567         }
1568
1569         sd_notifyf(false,
1570                    "STOPPING=1\n"
1571                    "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
1572         log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
1573
1574         server_destroy(&s);
1575
1576         free(arg_key);
1577         free(arg_cert);
1578         free(arg_trust);
1579
1580         return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1581 }