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