1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Zbigniew Jędrzejewski-Szmek
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.
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.
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/>.
27 #include <sys/prctl.h>
28 #include <sys/socket.h>
32 #include "sd-daemon.h"
33 #include "journal-file.h"
34 #include "journald-native.h"
35 #include "socket-util.h"
40 #include "conf-parser.h"
43 #include <gnutls/gnutls.h>
46 #include "journal-remote.h"
47 #include "journal-remote-write.h"
49 #define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
51 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
52 #define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
53 #define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
55 static char* arg_url = NULL;
56 static char* arg_getter = NULL;
57 static char* arg_listen_raw = NULL;
58 static char* arg_listen_http = NULL;
59 static char* arg_listen_https = NULL;
60 static char** arg_files = NULL;
61 static int arg_compress = true;
62 static int arg_seal = false;
63 static int http_socket = -1, https_socket = -1;
64 static char** arg_gnutls_log = NULL;
66 static JournalWriteSplitMode arg_split_mode = JOURNAL_WRITE_SPLIT_HOST;
67 static char* arg_output = NULL;
69 static char *arg_key = NULL;
70 static char *arg_cert = NULL;
71 static char *arg_trust = NULL;
72 static bool arg_trust_all = false;
74 /**********************************************************************
75 **********************************************************************
76 **********************************************************************/
78 static int spawn_child(const char* child, char** argv) {
80 pid_t parent_pid, child_pid;
84 return log_error_errno(errno, "Failed to create pager pipe: %m");
86 parent_pid = getpid();
91 log_error_errno(errno, "Failed to fork: %m");
98 r = dup2(fd[1], STDOUT_FILENO);
100 log_error_errno(errno, "Failed to dup pipe to stdout: %m");
106 /* Make sure the child goes away when the parent dies */
107 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
110 /* Check whether our parent died before we were able
111 * to set the death signal */
112 if (getppid() != parent_pid)
116 log_error_errno(errno, "Failed to exec child %s: %m", child);
122 log_warning_errno(errno, "Failed to close write end of pipe: %m");
127 static int spawn_curl(const char* url) {
128 char **argv = STRV_MAKE("curl",
129 "-HAccept: application/vnd.fdo.journal",
135 r = spawn_child("curl", argv);
137 log_error_errno(errno, "Failed to spawn curl: %m");
141 static int spawn_getter(const char *getter, const char *url) {
143 _cleanup_strv_free_ char **words = NULL;
146 r = strv_split_quoted(&words, getter, false);
148 return log_error_errno(r, "Failed to split getter option: %m");
150 r = strv_extend(&words, url);
152 return log_error_errno(r, "Failed to create command line: %m");
154 r = spawn_child(words[0], words);
156 log_error_errno(errno, "Failed to spawn getter %s: %m", getter);
161 #define filename_escape(s) xescape((s), "/ ")
163 static int open_output(Writer *w, const char* host) {
164 _cleanup_free_ char *_output = NULL;
168 switch (arg_split_mode) {
169 case JOURNAL_WRITE_SPLIT_NONE:
170 output = arg_output ?: REMOTE_JOURNAL_PATH "/remote.journal";
173 case JOURNAL_WRITE_SPLIT_HOST: {
174 _cleanup_free_ char *name;
178 name = filename_escape(host);
182 r = asprintf(&_output, "%s/remote-%s.journal",
183 arg_output ?: REMOTE_JOURNAL_PATH,
193 assert_not_reached("what?");
196 r = journal_file_open_reliably(output,
197 O_RDWR|O_CREAT, 0640,
198 arg_compress, arg_seal,
203 log_error_errno(r, "Failed to open output journal %s: %m",
206 log_info("Opened output file %s", w->journal->path);
210 /**********************************************************************
211 **********************************************************************
212 **********************************************************************/
214 static int init_writer_hashmap(RemoteServer *s) {
215 static const struct hash_ops *hash_ops[] = {
216 [JOURNAL_WRITE_SPLIT_NONE] = NULL,
217 [JOURNAL_WRITE_SPLIT_HOST] = &string_hash_ops,
220 assert(arg_split_mode >= 0 && arg_split_mode < (int) ELEMENTSOF(hash_ops));
222 s->writers = hashmap_new(hash_ops[arg_split_mode]);
229 static int get_writer(RemoteServer *s, const char *host,
232 _cleanup_writer_unref_ Writer *w = NULL;
235 switch(arg_split_mode) {
236 case JOURNAL_WRITE_SPLIT_NONE:
237 key = "one and only";
240 case JOURNAL_WRITE_SPLIT_HOST:
246 assert_not_reached("what split mode?");
249 w = hashmap_get(s->writers, key);
257 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST) {
258 w->hashmap_key = strdup(key);
263 r = open_output(w, host);
267 r = hashmap_put(s->writers, w->hashmap_key ?: key, w);
277 /**********************************************************************
278 **********************************************************************
279 **********************************************************************/
281 /* This should go away as soon as µhttpd allows state to be passed around. */
282 static RemoteServer *server;
284 static int dispatch_raw_source_event(sd_event_source *event,
288 static int dispatch_blocking_source_event(sd_event_source *event,
290 static int dispatch_raw_connection_event(sd_event_source *event,
294 static int dispatch_http_event(sd_event_source *event,
299 static int get_source_for_fd(RemoteServer *s,
300 int fd, char *name, RemoteSource **source) {
304 /* This takes ownership of name, but only on success. */
309 if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
312 r = get_writer(s, name, &writer);
314 return log_warning_errno(r, "Failed to get writer for source %s: %m",
317 if (s->sources[fd] == NULL) {
318 s->sources[fd] = source_new(fd, false, name, writer);
319 if (!s->sources[fd]) {
320 writer_unref(writer);
327 *source = s->sources[fd];
331 static int remove_source(RemoteServer *s, int fd) {
332 RemoteSource *source;
335 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
337 source = s->sources[fd];
339 /* this closes fd too */
341 s->sources[fd] = NULL;
348 static int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
350 RemoteSource *source;
353 /* This takes ownership of name, even on failure, if own_name is true. */
365 r = get_source_for_fd(s, fd, name, &source);
367 log_error_errno(r, "Failed to create source for fd:%d (%s): %m",
373 r = sd_event_add_io(s->events, &source->event,
374 fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
375 dispatch_raw_source_event, s);
377 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd, name);
378 r = sd_event_add_defer(s->events, &source->event,
379 dispatch_blocking_source_event, source);
381 sd_event_source_set_enabled(source->event, SD_EVENT_ON);
384 log_error_errno(r, "Failed to register event source for fd:%d: %m",
389 r = sd_event_source_set_description(source->event, name);
391 log_error_errno(r, "Failed to set source name for fd:%d: %m", fd);
395 return 1; /* work to do */
398 remove_source(s, fd);
402 static int add_raw_socket(RemoteServer *s, int fd) {
404 _cleanup_close_ int fd_ = fd;
405 char name[sizeof("raw-socket-")-1 + DECIMAL_STR_MAX(int) + 1];
409 r = sd_event_add_io(s->events, &s->listen_event,
411 dispatch_raw_connection_event, s);
415 xsprintf(name, "raw-socket-%d", fd);
417 r = sd_event_source_set_description(s->listen_event, name);
426 static int setup_raw_socket(RemoteServer *s, const char *address) {
429 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
433 return add_raw_socket(s, fd);
436 /**********************************************************************
437 **********************************************************************
438 **********************************************************************/
440 static int request_meta(void **connection_cls, int fd, char *hostname) {
441 RemoteSource *source;
445 assert(connection_cls);
449 r = get_writer(server, hostname, &writer);
451 return log_warning_errno(r, "Failed to get writer for source %s: %m",
454 source = source_new(fd, true, hostname, writer);
456 writer_unref(writer);
460 log_debug("Added RemoteSource as connection metadata %p", source);
462 *connection_cls = source;
466 static void request_meta_free(void *cls,
467 struct MHD_Connection *connection,
468 void **connection_cls,
469 enum MHD_RequestTerminationCode toe) {
472 assert(connection_cls);
476 log_debug("Cleaning up connection metadata %p", s);
478 *connection_cls = NULL;
482 static int process_http_upload(
483 struct MHD_Connection *connection,
484 const char *upload_data,
485 size_t *upload_data_size,
486 RemoteSource *source) {
488 bool finished = false;
494 log_trace("%s: connection %p, %zu bytes",
495 __func__, connection, *upload_data_size);
497 if (*upload_data_size) {
498 log_trace("Received %zu bytes", *upload_data_size);
500 r = push_data(source, upload_data, *upload_data_size);
502 return mhd_respond_oom(connection);
504 *upload_data_size = 0;
509 r = process_source(source, arg_compress, arg_seal);
510 if (r == -EAGAIN || r == -EWOULDBLOCK)
513 log_warning("Failed to process data for connection %p", connection);
515 return mhd_respondf(connection,
516 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
517 "Entry is too large, maximum is %u bytes.\n",
520 return mhd_respondf(connection,
521 MHD_HTTP_UNPROCESSABLE_ENTITY,
522 "Processing failed: %s.", strerror(-r));
529 /* The upload is finished */
531 remaining = source_non_empty(source);
533 log_warning("Premature EOFbyte. %zu bytes lost.", remaining);
534 return mhd_respondf(connection, MHD_HTTP_EXPECTATION_FAILED,
535 "Premature EOF. %zu bytes of trailing data not processed.",
539 return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
542 static int request_handler(
544 struct MHD_Connection *connection,
548 const char *upload_data,
549 size_t *upload_data_size,
550 void **connection_cls) {
554 _cleanup_free_ char *hostname = NULL;
557 assert(connection_cls);
561 log_trace("Handling a connection %s %s %s", method, url, version);
564 return process_http_upload(connection,
565 upload_data, upload_data_size,
568 if (!streq(method, "POST"))
569 return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
570 "Unsupported method.\n");
572 if (!streq(url, "/upload"))
573 return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
576 header = MHD_lookup_connection_value(connection,
577 MHD_HEADER_KIND, "Content-Type");
578 if (!header || !streq(header, "application/vnd.fdo.journal"))
579 return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
580 "Content-Type: application/vnd.fdo.journal"
584 const union MHD_ConnectionInfo *ci;
586 ci = MHD_get_connection_info(connection,
587 MHD_CONNECTION_INFO_CONNECTION_FD);
589 log_error("MHD_get_connection_info failed: cannot get remote fd");
590 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
591 "Cannot check remote address");
598 if (server->check_trust) {
599 r = check_permissions(connection, &code, &hostname);
603 r = getnameinfo_pretty(fd, &hostname);
605 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
606 "Cannot check remote hostname");
612 r = request_meta(connection_cls, fd, hostname);
614 return respond_oom(connection);
616 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
623 static int setup_microhttpd_server(RemoteServer *s,
628 struct MHD_OptionItem opts[] = {
629 { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
630 { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
631 { MHD_OPTION_LISTEN_SOCKET, fd},
639 MHD_USE_PEDANTIC_CHECKS |
640 MHD_USE_EPOLL_LINUX_ONLY |
643 const union MHD_DaemonInfo *info;
649 r = fd_nonblock(fd, true);
651 return log_error_errno(r, "Failed to make fd:%d nonblocking: %m", fd);
656 opts[opts_pos++] = (struct MHD_OptionItem)
657 {MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
658 opts[opts_pos++] = (struct MHD_OptionItem)
659 {MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
661 flags |= MHD_USE_SSL;
664 opts[opts_pos++] = (struct MHD_OptionItem)
665 {MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
668 d = new(MHDDaemonWrapper, 1);
672 d->fd = (uint64_t) fd;
674 d->daemon = MHD_start_daemon(flags, 0,
676 request_handler, NULL,
677 MHD_OPTION_ARRAY, opts,
680 log_error("Failed to start µhttp daemon");
685 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
686 key ? "HTTPS" : "HTTP", fd, d);
689 info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
691 log_error("µhttp returned NULL daemon info");
696 epoll_fd = info->listen_fd;
698 log_error("µhttp epoll fd is invalid");
703 r = sd_event_add_io(s->events, &d->event,
705 dispatch_http_event, d);
707 log_error_errno(r, "Failed to add event callback: %m");
711 r = sd_event_source_set_description(d->event, "epoll-fd");
713 log_error_errno(r, "Failed to set source name: %m");
717 r = hashmap_ensure_allocated(&s->daemons, &uint64_hash_ops);
723 r = hashmap_put(s->daemons, &d->fd, d);
725 log_error_errno(r, "Failed to add daemon to hashmap: %m");
733 MHD_stop_daemon(d->daemon);
739 static int setup_microhttpd_socket(RemoteServer *s,
746 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
750 return setup_microhttpd_server(s, fd, key, cert, trust);
753 static int dispatch_http_event(sd_event_source *event,
757 MHDDaemonWrapper *d = userdata;
762 r = MHD_run(d->daemon);
764 log_error("MHD_run failed!");
765 // XXX: unregister daemon
769 return 1; /* work to do */
772 /**********************************************************************
773 **********************************************************************
774 **********************************************************************/
776 static int setup_signals(RemoteServer *s) {
782 assert_se(sigemptyset(&mask) == 0);
783 sigset_add_many(&mask, SIGINT, SIGTERM, -1);
784 assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
786 r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, NULL, s);
790 r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, NULL, s);
797 static int negative_fd(const char *spec) {
798 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
802 r = safe_atoi(spec, &fd);
812 static int remoteserver_init(RemoteServer *s,
821 if ((arg_listen_raw || arg_listen_http) && trust) {
822 log_error("Option --trust makes all non-HTTPS connections untrusted.");
826 r = sd_event_default(&s->events);
828 return log_error_errno(r, "Failed to allocate event loop: %m");
832 assert(server == NULL);
835 r = init_writer_hashmap(s);
839 n = sd_listen_fds(true);
841 return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
843 log_info("Received %d descriptors", n);
845 if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
846 log_error("Received fewer sockets than expected");
850 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
851 if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
852 log_info("Received a listening socket (fd:%d)", fd);
854 if (fd == http_socket)
855 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
856 else if (fd == https_socket)
857 r = setup_microhttpd_server(s, fd, key, cert, trust);
859 r = add_raw_socket(s, fd);
860 } else if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
863 r = getnameinfo_pretty(fd, &hostname);
865 return log_error_errno(r, "Failed to retrieve remote name: %m");
867 log_info("Received a connection socket (fd:%d) from %s", fd, hostname);
869 r = add_source(s, fd, hostname, true);
871 log_error("Unknown socket passed on fd:%d", fd);
877 return log_error_errno(r, "Failed to register socket (fd:%d): %m",
882 const char *url, *hostname;
884 url = strjoina(arg_url, "/entries");
887 log_info("Spawning getter %s...", url);
888 fd = spawn_getter(arg_getter, url);
890 log_info("Spawning curl %s...", url);
891 fd = spawn_curl(url);
897 startswith(arg_url, "https://") ?:
898 startswith(arg_url, "http://") ?:
901 r = add_source(s, fd, (char*) hostname, false);
906 if (arg_listen_raw) {
907 log_info("Listening on a socket...");
908 r = setup_raw_socket(s, arg_listen_raw);
913 if (arg_listen_http) {
914 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
919 if (arg_listen_https) {
920 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
925 STRV_FOREACH(file, arg_files) {
926 const char *output_name;
928 if (streq(*file, "-")) {
929 log_info("Using standard input as source.");
932 output_name = "stdin";
934 log_info("Reading file %s...", *file);
936 fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
938 return log_error_errno(errno, "Failed to open %s: %m", *file);
942 r = add_source(s, fd, (char*) output_name, false);
947 if (s->active == 0) {
948 log_error("Zarro sources specified");
952 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) {
953 /* In this case we know what the writer will be
954 called, so we can create it and verify that we can
955 create output as expected. */
956 r = get_writer(s, NULL, &s->_single_writer);
964 static void server_destroy(RemoteServer *s) {
968 while ((d = hashmap_steal_first(s->daemons))) {
969 MHD_stop_daemon(d->daemon);
970 sd_event_source_unref(d->event);
974 hashmap_free(s->daemons);
976 assert(s->sources_size == 0 || s->sources);
977 for (i = 0; i < s->sources_size; i++)
981 writer_unref(s->_single_writer);
982 hashmap_free(s->writers);
984 sd_event_source_unref(s->sigterm_event);
985 sd_event_source_unref(s->sigint_event);
986 sd_event_source_unref(s->listen_event);
987 sd_event_unref(s->events);
989 /* fds that we're listening on remain open... */
992 /**********************************************************************
993 **********************************************************************
994 **********************************************************************/
996 static int dispatch_raw_source_event(sd_event_source *event,
1001 RemoteServer *s = userdata;
1002 RemoteSource *source;
1005 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
1006 source = s->sources[fd];
1007 assert(source->fd == fd);
1009 r = process_source(source, arg_compress, arg_seal);
1010 if (source->state == STATE_EOF) {
1013 log_info("EOF reached with source fd:%d (%s)",
1014 source->fd, source->name);
1016 remaining = source_non_empty(source);
1018 log_warning("Premature EOF. %zu bytes lost.", remaining);
1019 remove_source(s, source->fd);
1020 log_info("%zu active sources remaining", s->active);
1022 } else if (r == -E2BIG) {
1023 log_error("Entry too big, skipped");
1025 } else if (r == -EAGAIN) {
1028 log_info_errno(r, "Closing connection: %m");
1029 remove_source(server, fd);
1035 static int dispatch_blocking_source_event(sd_event_source *event,
1037 RemoteSource *source = userdata;
1039 return dispatch_raw_source_event(event, source->fd, EPOLLIN, server);
1042 static int accept_connection(const char* type, int fd,
1043 SocketAddress *addr, char **hostname) {
1046 log_debug("Accepting new %s connection on fd:%d", type, fd);
1047 fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
1049 return log_error_errno(errno, "accept() on fd:%d failed: %m", fd);
1051 switch(socket_address_family(addr)) {
1054 _cleanup_free_ char *a = NULL;
1057 r = socket_address_print(addr, &a);
1059 log_error_errno(r, "socket_address_print(): %m");
1064 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
1070 log_info("Accepted %s %s connection from %s",
1072 socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
1080 log_error("Rejected %s connection with unsupported family %d",
1081 type, socket_address_family(addr));
1088 static int dispatch_raw_connection_event(sd_event_source *event,
1092 RemoteServer *s = userdata;
1094 SocketAddress addr = {
1095 .size = sizeof(union sockaddr_union),
1096 .type = SOCK_STREAM,
1100 fd2 = accept_connection("raw", fd, &addr, &hostname);
1104 return add_source(s, fd2, hostname, true);
1107 /**********************************************************************
1108 **********************************************************************
1109 **********************************************************************/
1111 static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
1112 [JOURNAL_WRITE_SPLIT_NONE] = "none",
1113 [JOURNAL_WRITE_SPLIT_HOST] = "host",
1116 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
1117 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
1118 journal_write_split_mode,
1119 JournalWriteSplitMode,
1120 "Failed to parse split mode setting");
1122 static int parse_config(void) {
1123 const ConfigTableItem items[] = {
1124 { "Remote", "SplitMode", config_parse_write_split_mode, 0, &arg_split_mode },
1125 { "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key },
1126 { "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert },
1127 { "Remote", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
1130 return config_parse_many(PKGSYSCONFDIR "/journal-remote.conf",
1131 CONF_DIRS_NULSTR("systemd/journal-remote.conf"),
1132 "Remote\0", config_item_table_lookup, items,
1136 static void help(void) {
1137 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1138 "Write external journal events to journal file(s).\n\n"
1139 " -h --help Show this help\n"
1140 " --version Show package version\n"
1141 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1142 " --getter=COMMAND Read events from the output of COMMAND\n"
1143 " --listen-raw=ADDR Listen for connections at ADDR\n"
1144 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1145 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1146 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1147 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1148 " --seal[=BOOL] Use event sealing (default: no)\n"
1149 " --key=FILENAME SSL key in PEM format (default:\n"
1150 " \"" PRIV_KEY_FILE "\")\n"
1151 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1152 " \"" CERT_FILE "\")\n"
1153 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1154 " \"" TRUST_FILE "\")\n"
1155 " --gnutls-log=CATEGORY...\n"
1156 " Specify a list of gnutls logging categories\n"
1157 " --split-mode=none|host How many output files to create\n"
1159 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1160 , program_invocation_short_name);
1163 static int parse_argv(int argc, char *argv[]) {
1165 ARG_VERSION = 0x100,
1180 static const struct option options[] = {
1181 { "help", no_argument, NULL, 'h' },
1182 { "version", no_argument, NULL, ARG_VERSION },
1183 { "url", required_argument, NULL, ARG_URL },
1184 { "getter", required_argument, NULL, ARG_GETTER },
1185 { "listen-raw", required_argument, NULL, ARG_LISTEN_RAW },
1186 { "listen-http", required_argument, NULL, ARG_LISTEN_HTTP },
1187 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1188 { "output", required_argument, NULL, 'o' },
1189 { "split-mode", required_argument, NULL, ARG_SPLIT_MODE },
1190 { "compress", optional_argument, NULL, ARG_COMPRESS },
1191 { "seal", optional_argument, NULL, ARG_SEAL },
1192 { "key", required_argument, NULL, ARG_KEY },
1193 { "cert", required_argument, NULL, ARG_CERT },
1194 { "trust", required_argument, NULL, ARG_TRUST },
1195 { "gnutls-log", required_argument, NULL, ARG_GNUTLS_LOG },
1200 bool type_a, type_b;
1205 while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1209 return 0 /* done */;
1212 puts(PACKAGE_STRING);
1213 puts(SYSTEMD_FEATURES);
1214 return 0 /* done */;
1218 log_error("cannot currently set more than one --url");
1227 log_error("cannot currently use --getter more than once");
1231 arg_getter = optarg;
1234 case ARG_LISTEN_RAW:
1235 if (arg_listen_raw) {
1236 log_error("cannot currently use --listen-raw more than once");
1240 arg_listen_raw = optarg;
1243 case ARG_LISTEN_HTTP:
1244 if (arg_listen_http || http_socket >= 0) {
1245 log_error("cannot currently use --listen-http more than once");
1249 r = negative_fd(optarg);
1253 arg_listen_http = optarg;
1256 case ARG_LISTEN_HTTPS:
1257 if (arg_listen_https || https_socket >= 0) {
1258 log_error("cannot currently use --listen-https more than once");
1262 r = negative_fd(optarg);
1266 arg_listen_https = optarg;
1272 log_error("Key file specified twice");
1276 arg_key = strdup(optarg);
1284 log_error("Certificate file specified twice");
1288 arg_cert = strdup(optarg);
1295 if (arg_trust || arg_trust_all) {
1296 log_error("Confusing trusted CA configuration");
1300 if (streq(optarg, "all"))
1301 arg_trust_all = true;
1304 arg_trust = strdup(optarg);
1308 log_error("Option --trust is not available.");
1317 log_error("cannot use --output/-o more than once");
1321 arg_output = optarg;
1324 case ARG_SPLIT_MODE:
1325 arg_split_mode = journal_write_split_mode_from_string(optarg);
1326 if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) {
1327 log_error("Invalid split mode: %s", optarg);
1334 r = parse_boolean(optarg);
1336 log_error("Failed to parse --compress= parameter.");
1342 arg_compress = true;
1348 r = parse_boolean(optarg);
1350 log_error("Failed to parse --seal= parameter.");
1360 case ARG_GNUTLS_LOG: {
1362 const char *word, *state;
1365 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
1368 cat = strndup(word, size);
1372 if (strv_consume(&arg_gnutls_log, cat) < 0)
1377 log_error("Option --gnutls-log is not available.");
1386 assert_not_reached("Unknown option code.");
1390 arg_files = argv + optind;
1392 type_a = arg_getter || !strv_isempty(arg_files);
1395 || arg_listen_http || arg_listen_https
1396 || sd_listen_fds(false) > 0;
1397 if (type_a && type_b) {
1398 log_error("Cannot use file input or --getter with "
1399 "--arg-listen-... or socket activation.");
1404 log_error("Option --output must be specified with file input or --getter.");
1408 arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
1411 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE
1412 && arg_output && is_dir(arg_output, true) > 0) {
1413 log_error("For SplitMode=none, output must be a file.");
1417 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
1418 && arg_output && is_dir(arg_output, true) <= 0) {
1419 log_error("For SplitMode=host, output must be a directory.");
1423 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1424 journal_write_split_mode_to_string(arg_split_mode),
1429 return 1 /* work to do */;
1432 static int load_certificates(char **key, char **cert, char **trust) {
1435 r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
1437 return log_error_errno(r, "Failed to read key from file '%s': %m",
1438 arg_key ?: PRIV_KEY_FILE);
1440 r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1442 return log_error_errno(r, "Failed to read certificate from file '%s': %m",
1443 arg_cert ?: CERT_FILE);
1446 log_info("Certificate checking disabled.");
1448 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1450 return log_error_errno(r, "Failed to read CA certificate file '%s': %m",
1451 arg_trust ?: TRUST_FILE);
1457 static int setup_gnutls_logger(char **categories) {
1458 if (!arg_listen_http && !arg_listen_https)
1466 gnutls_global_set_log_function(log_func_gnutls);
1469 STRV_FOREACH(cat, categories) {
1470 r = log_enable_gnutls_category(*cat);
1475 log_reset_gnutls_level();
1482 int main(int argc, char **argv) {
1483 RemoteServer s = {};
1485 _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1487 log_show_color(true);
1488 log_parse_environment();
1492 return EXIT_FAILURE;
1494 r = parse_argv(argc, argv);
1496 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1498 r = setup_gnutls_logger(arg_gnutls_log);
1500 return EXIT_FAILURE;
1502 if (arg_listen_https || https_socket >= 0)
1503 if (load_certificates(&key, &cert, &trust) < 0)
1504 return EXIT_FAILURE;
1506 if (remoteserver_init(&s, key, cert, trust) < 0)
1507 return EXIT_FAILURE;
1509 r = sd_event_set_watchdog(s.events, true);
1511 log_error_errno(r, "Failed to enable watchdog: %m");
1513 log_debug("Watchdog is %s.", r > 0 ? "enabled" : "disabled");
1515 log_debug("%s running as pid "PID_FMT,
1516 program_invocation_short_name, getpid());
1519 "STATUS=Processing requests...");
1522 r = sd_event_get_state(s.events);
1525 if (r == SD_EVENT_FINISHED)
1528 r = sd_event_run(s.events, -1);
1530 log_error_errno(r, "Failed to run event loop: %m");
1537 "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
1538 log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
1546 return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;