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