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