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