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