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