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