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