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