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, 0);
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_debug("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_raw_source_until_block(sd_event_source *event,
290 static int dispatch_blocking_source_event(sd_event_source *event,
292 static int dispatch_raw_connection_event(sd_event_source *event,
296 static int dispatch_http_event(sd_event_source *event,
301 static int get_source_for_fd(RemoteServer *s,
302 int fd, char *name, RemoteSource **source) {
306 /* This takes ownership of name, but only on success. */
311 if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
314 r = get_writer(s, name, &writer);
316 return log_warning_errno(r, "Failed to get writer for source %s: %m",
319 if (s->sources[fd] == NULL) {
320 s->sources[fd] = source_new(fd, false, name, writer);
321 if (!s->sources[fd]) {
322 writer_unref(writer);
329 *source = s->sources[fd];
333 static int remove_source(RemoteServer *s, int fd) {
334 RemoteSource *source;
337 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
339 source = s->sources[fd];
341 /* this closes fd too */
343 s->sources[fd] = NULL;
350 static int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
352 RemoteSource *source = NULL;
355 /* This takes ownership of name, even on failure, if own_name is true. */
367 r = get_source_for_fd(s, fd, name, &source);
369 log_error_errno(r, "Failed to create source for fd:%d (%s): %m",
375 r = sd_event_add_io(s->events, &source->event,
376 fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
377 dispatch_raw_source_event, source);
379 /* Add additional source for buffer processing. It will be
381 r = sd_event_add_defer(s->events, &source->buffer_event,
382 dispatch_raw_source_until_block, source);
384 sd_event_source_set_enabled(source->buffer_event, SD_EVENT_OFF);
385 } else if (r == -EPERM) {
386 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd, name);
387 r = sd_event_add_defer(s->events, &source->event,
388 dispatch_blocking_source_event, source);
390 sd_event_source_set_enabled(source->event, SD_EVENT_ON);
393 log_error_errno(r, "Failed to register event source for fd:%d: %m",
398 r = sd_event_source_set_description(source->event, name);
400 log_error_errno(r, "Failed to set source name for fd:%d: %m", fd);
404 return 1; /* work to do */
407 remove_source(s, fd);
411 static int add_raw_socket(RemoteServer *s, int fd) {
413 _cleanup_close_ int fd_ = fd;
414 char name[sizeof("raw-socket-")-1 + DECIMAL_STR_MAX(int) + 1];
418 r = sd_event_add_io(s->events, &s->listen_event,
420 dispatch_raw_connection_event, s);
424 xsprintf(name, "raw-socket-%d", fd);
426 r = sd_event_source_set_description(s->listen_event, name);
435 static int setup_raw_socket(RemoteServer *s, const char *address) {
438 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
442 return add_raw_socket(s, fd);
445 /**********************************************************************
446 **********************************************************************
447 **********************************************************************/
449 static int request_meta(void **connection_cls, int fd, char *hostname) {
450 RemoteSource *source;
454 assert(connection_cls);
458 r = get_writer(server, hostname, &writer);
460 return log_warning_errno(r, "Failed to get writer for source %s: %m",
463 source = source_new(fd, true, hostname, writer);
465 writer_unref(writer);
469 log_debug("Added RemoteSource as connection metadata %p", source);
471 *connection_cls = source;
475 static void request_meta_free(void *cls,
476 struct MHD_Connection *connection,
477 void **connection_cls,
478 enum MHD_RequestTerminationCode toe) {
481 assert(connection_cls);
485 log_debug("Cleaning up connection metadata %p", s);
487 *connection_cls = NULL;
491 static int process_http_upload(
492 struct MHD_Connection *connection,
493 const char *upload_data,
494 size_t *upload_data_size,
495 RemoteSource *source) {
497 bool finished = false;
503 log_trace("%s: connection %p, %zu bytes",
504 __func__, connection, *upload_data_size);
506 if (*upload_data_size) {
507 log_trace("Received %zu bytes", *upload_data_size);
509 r = push_data(source, upload_data, *upload_data_size);
511 return mhd_respond_oom(connection);
513 *upload_data_size = 0;
518 r = process_source(source, arg_compress, arg_seal);
522 log_warning("Failed to process data for connection %p", connection);
524 return mhd_respondf(connection,
525 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
526 "Entry is too large, maximum is %u bytes.\n",
529 return mhd_respondf(connection,
530 MHD_HTTP_UNPROCESSABLE_ENTITY,
531 "Processing failed: %s.", strerror(-r));
538 /* The upload is finished */
540 remaining = source_non_empty(source);
542 log_warning("Premature EOFbyte. %zu bytes lost.", remaining);
543 return mhd_respondf(connection, MHD_HTTP_EXPECTATION_FAILED,
544 "Premature EOF. %zu bytes of trailing data not processed.",
548 return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
551 static int request_handler(
553 struct MHD_Connection *connection,
557 const char *upload_data,
558 size_t *upload_data_size,
559 void **connection_cls) {
563 _cleanup_free_ char *hostname = NULL;
566 assert(connection_cls);
570 log_trace("Handling a connection %s %s %s", method, url, version);
573 return process_http_upload(connection,
574 upload_data, upload_data_size,
577 if (!streq(method, "POST"))
578 return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
579 "Unsupported method.\n");
581 if (!streq(url, "/upload"))
582 return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
585 header = MHD_lookup_connection_value(connection,
586 MHD_HEADER_KIND, "Content-Type");
587 if (!header || !streq(header, "application/vnd.fdo.journal"))
588 return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
589 "Content-Type: application/vnd.fdo.journal"
593 const union MHD_ConnectionInfo *ci;
595 ci = MHD_get_connection_info(connection,
596 MHD_CONNECTION_INFO_CONNECTION_FD);
598 log_error("MHD_get_connection_info failed: cannot get remote fd");
599 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
600 "Cannot check remote address");
607 if (server->check_trust) {
608 r = check_permissions(connection, &code, &hostname);
612 r = getnameinfo_pretty(fd, &hostname);
614 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
615 "Cannot check remote hostname");
621 r = request_meta(connection_cls, fd, hostname);
623 return respond_oom(connection);
625 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
632 static int setup_microhttpd_server(RemoteServer *s,
637 struct MHD_OptionItem opts[] = {
638 { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
639 { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
640 { MHD_OPTION_LISTEN_SOCKET, fd},
648 MHD_USE_PEDANTIC_CHECKS |
649 MHD_USE_EPOLL_LINUX_ONLY |
652 const union MHD_DaemonInfo *info;
658 r = fd_nonblock(fd, true);
660 return log_error_errno(r, "Failed to make fd:%d nonblocking: %m", fd);
665 opts[opts_pos++] = (struct MHD_OptionItem)
666 {MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
667 opts[opts_pos++] = (struct MHD_OptionItem)
668 {MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
670 flags |= MHD_USE_SSL;
673 opts[opts_pos++] = (struct MHD_OptionItem)
674 {MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
677 d = new(MHDDaemonWrapper, 1);
681 d->fd = (uint64_t) fd;
683 d->daemon = MHD_start_daemon(flags, 0,
685 request_handler, NULL,
686 MHD_OPTION_ARRAY, opts,
689 log_error("Failed to start µhttp daemon");
694 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
695 key ? "HTTPS" : "HTTP", fd, d);
698 info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
700 log_error("µhttp returned NULL daemon info");
705 epoll_fd = info->listen_fd;
707 log_error("µhttp epoll fd is invalid");
712 r = sd_event_add_io(s->events, &d->event,
714 dispatch_http_event, d);
716 log_error_errno(r, "Failed to add event callback: %m");
720 r = sd_event_source_set_description(d->event, "epoll-fd");
722 log_error_errno(r, "Failed to set source name: %m");
726 r = hashmap_ensure_allocated(&s->daemons, &uint64_hash_ops);
732 r = hashmap_put(s->daemons, &d->fd, d);
734 log_error_errno(r, "Failed to add daemon to hashmap: %m");
742 MHD_stop_daemon(d->daemon);
748 static int setup_microhttpd_socket(RemoteServer *s,
755 fd = make_socket_fd(LOG_DEBUG, address, SOCK_STREAM | SOCK_CLOEXEC);
759 return setup_microhttpd_server(s, fd, key, cert, trust);
762 static int dispatch_http_event(sd_event_source *event,
766 MHDDaemonWrapper *d = userdata;
771 r = MHD_run(d->daemon);
773 log_error("MHD_run failed!");
774 // XXX: unregister daemon
778 return 1; /* work to do */
781 /**********************************************************************
782 **********************************************************************
783 **********************************************************************/
785 static int setup_signals(RemoteServer *s) {
791 assert_se(sigemptyset(&mask) == 0);
792 sigset_add_many(&mask, SIGINT, SIGTERM, -1);
793 assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
795 r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, NULL, s);
799 r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, NULL, s);
806 static int negative_fd(const char *spec) {
807 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
811 r = safe_atoi(spec, &fd);
821 static int remoteserver_init(RemoteServer *s,
830 if ((arg_listen_raw || arg_listen_http) && trust) {
831 log_error("Option --trust makes all non-HTTPS connections untrusted.");
835 r = sd_event_default(&s->events);
837 return log_error_errno(r, "Failed to allocate event loop: %m");
841 assert(server == NULL);
844 r = init_writer_hashmap(s);
848 n = sd_listen_fds(true);
850 return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
852 log_debug("Received %d descriptors", n);
854 if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
855 log_error("Received fewer sockets than expected");
859 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
860 if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
861 log_debug("Received a listening socket (fd:%d)", fd);
863 if (fd == http_socket)
864 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
865 else if (fd == https_socket)
866 r = setup_microhttpd_server(s, fd, key, cert, trust);
868 r = add_raw_socket(s, fd);
869 } else if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
872 r = getnameinfo_pretty(fd, &hostname);
874 return log_error_errno(r, "Failed to retrieve remote name: %m");
876 log_debug("Received a connection socket (fd:%d) from %s", fd, hostname);
878 r = add_source(s, fd, hostname, true);
880 log_error("Unknown socket passed on fd:%d", fd);
886 return log_error_errno(r, "Failed to register socket (fd:%d): %m",
891 const char *url, *hostname;
893 url = strjoina(arg_url, "/entries");
896 log_info("Spawning getter %s...", url);
897 fd = spawn_getter(arg_getter, url);
899 log_info("Spawning curl %s...", url);
900 fd = spawn_curl(url);
906 startswith(arg_url, "https://") ?:
907 startswith(arg_url, "http://") ?:
910 r = add_source(s, fd, (char*) hostname, false);
915 if (arg_listen_raw) {
916 log_debug("Listening on a socket...");
917 r = setup_raw_socket(s, arg_listen_raw);
922 if (arg_listen_http) {
923 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
928 if (arg_listen_https) {
929 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
934 STRV_FOREACH(file, arg_files) {
935 const char *output_name;
937 if (streq(*file, "-")) {
938 log_debug("Using standard input as source.");
941 output_name = "stdin";
943 log_debug("Reading file %s...", *file);
945 fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
947 return log_error_errno(errno, "Failed to open %s: %m", *file);
951 r = add_source(s, fd, (char*) output_name, false);
956 if (s->active == 0) {
957 log_error("Zarro sources specified");
961 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) {
962 /* In this case we know what the writer will be
963 called, so we can create it and verify that we can
964 create output as expected. */
965 r = get_writer(s, NULL, &s->_single_writer);
973 static void server_destroy(RemoteServer *s) {
977 while ((d = hashmap_steal_first(s->daemons))) {
978 MHD_stop_daemon(d->daemon);
979 sd_event_source_unref(d->event);
983 hashmap_free(s->daemons);
985 assert(s->sources_size == 0 || s->sources);
986 for (i = 0; i < s->sources_size; i++)
990 writer_unref(s->_single_writer);
991 hashmap_free(s->writers);
993 sd_event_source_unref(s->sigterm_event);
994 sd_event_source_unref(s->sigint_event);
995 sd_event_source_unref(s->listen_event);
996 sd_event_unref(s->events);
998 /* fds that we're listening on remain open... */
1001 /**********************************************************************
1002 **********************************************************************
1003 **********************************************************************/
1005 static int handle_raw_source(sd_event_source *event,
1010 RemoteSource *source;
1013 /* Returns 1 if there might be more data pending,
1014 * 0 if data is currently exhausted, negative on error.
1017 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
1018 source = s->sources[fd];
1019 assert(source->fd == fd);
1021 r = process_source(source, arg_compress, arg_seal);
1022 if (source->state == STATE_EOF) {
1025 log_debug("EOF reached with source fd:%d (%s)",
1026 source->fd, source->name);
1028 remaining = source_non_empty(source);
1030 log_notice("Premature EOF. %zu bytes lost.", remaining);
1031 remove_source(s, source->fd);
1032 log_debug("%zu active sources remaining", s->active);
1034 } else if (r == -E2BIG) {
1035 log_notice_errno(E2BIG, "Entry too big, skipped");
1037 } else if (r == -EAGAIN) {
1040 log_debug_errno(r, "Closing connection: %m");
1041 remove_source(server, fd);
1047 static int dispatch_raw_source_until_block(sd_event_source *event,
1049 RemoteSource *source = userdata;
1052 /* Make sure event stays around even if source is destroyed */
1053 sd_event_source_ref(event);
1055 r = handle_raw_source(event, source->fd, EPOLLIN, server);
1057 /* No more data for now */
1058 sd_event_source_set_enabled(event, SD_EVENT_OFF);
1060 sd_event_source_unref(event);
1065 static int dispatch_raw_source_event(sd_event_source *event,
1069 RemoteSource *source = userdata;
1072 assert(source->event);
1073 assert(source->buffer_event);
1075 r = handle_raw_source(event, fd, EPOLLIN, server);
1077 /* Might have more data. We need to rerun the handler
1078 * until we are sure the buffer is exhausted. */
1079 sd_event_source_set_enabled(source->buffer_event, SD_EVENT_ON);
1084 static int dispatch_blocking_source_event(sd_event_source *event,
1086 RemoteSource *source = userdata;
1088 return handle_raw_source(event, source->fd, EPOLLIN, server);
1091 static int accept_connection(const char* type, int fd,
1092 SocketAddress *addr, char **hostname) {
1095 log_debug("Accepting new %s connection on fd:%d", type, fd);
1096 fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
1098 return log_error_errno(errno, "accept() on fd:%d failed: %m", fd);
1100 switch(socket_address_family(addr)) {
1103 _cleanup_free_ char *a = NULL;
1106 r = socket_address_print(addr, &a);
1108 log_error_errno(r, "socket_address_print(): %m");
1113 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
1119 log_debug("Accepted %s %s connection from %s",
1121 socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
1129 log_error("Rejected %s connection with unsupported family %d",
1130 type, socket_address_family(addr));
1137 static int dispatch_raw_connection_event(sd_event_source *event,
1141 RemoteServer *s = userdata;
1143 SocketAddress addr = {
1144 .size = sizeof(union sockaddr_union),
1145 .type = SOCK_STREAM,
1147 char *hostname = NULL;
1149 fd2 = accept_connection("raw", fd, &addr, &hostname);
1153 return add_source(s, fd2, hostname, true);
1156 /**********************************************************************
1157 **********************************************************************
1158 **********************************************************************/
1160 static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
1161 [JOURNAL_WRITE_SPLIT_NONE] = "none",
1162 [JOURNAL_WRITE_SPLIT_HOST] = "host",
1165 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
1166 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
1167 journal_write_split_mode,
1168 JournalWriteSplitMode,
1169 "Failed to parse split mode setting");
1171 static int parse_config(void) {
1172 const ConfigTableItem items[] = {
1173 { "Remote", "SplitMode", config_parse_write_split_mode, 0, &arg_split_mode },
1174 { "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key },
1175 { "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert },
1176 { "Remote", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
1179 return config_parse_many(PKGSYSCONFDIR "/journal-remote.conf",
1180 CONF_DIRS_NULSTR("systemd/journal-remote.conf"),
1181 "Remote\0", config_item_table_lookup, items,
1185 static void help(void) {
1186 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1187 "Write external journal events to journal file(s).\n\n"
1188 " -h --help Show this help\n"
1189 " --version Show package version\n"
1190 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1191 " --getter=COMMAND Read events from the output of COMMAND\n"
1192 " --listen-raw=ADDR Listen for connections at ADDR\n"
1193 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1194 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1195 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1196 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1197 " --seal[=BOOL] Use event sealing (default: no)\n"
1198 " --key=FILENAME SSL key in PEM format (default:\n"
1199 " \"" PRIV_KEY_FILE "\")\n"
1200 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1201 " \"" CERT_FILE "\")\n"
1202 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1203 " \"" TRUST_FILE "\")\n"
1204 " --gnutls-log=CATEGORY...\n"
1205 " Specify a list of gnutls logging categories\n"
1206 " --split-mode=none|host How many output files to create\n"
1208 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1209 , program_invocation_short_name);
1212 static int parse_argv(int argc, char *argv[]) {
1214 ARG_VERSION = 0x100,
1229 static const struct option options[] = {
1230 { "help", no_argument, NULL, 'h' },
1231 { "version", no_argument, NULL, ARG_VERSION },
1232 { "url", required_argument, NULL, ARG_URL },
1233 { "getter", required_argument, NULL, ARG_GETTER },
1234 { "listen-raw", required_argument, NULL, ARG_LISTEN_RAW },
1235 { "listen-http", required_argument, NULL, ARG_LISTEN_HTTP },
1236 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1237 { "output", required_argument, NULL, 'o' },
1238 { "split-mode", required_argument, NULL, ARG_SPLIT_MODE },
1239 { "compress", optional_argument, NULL, ARG_COMPRESS },
1240 { "seal", optional_argument, NULL, ARG_SEAL },
1241 { "key", required_argument, NULL, ARG_KEY },
1242 { "cert", required_argument, NULL, ARG_CERT },
1243 { "trust", required_argument, NULL, ARG_TRUST },
1244 { "gnutls-log", required_argument, NULL, ARG_GNUTLS_LOG },
1249 bool type_a, type_b;
1254 while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1258 return 0 /* done */;
1261 puts(PACKAGE_STRING);
1262 puts(SYSTEMD_FEATURES);
1263 return 0 /* done */;
1267 log_error("cannot currently set more than one --url");
1276 log_error("cannot currently use --getter more than once");
1280 arg_getter = optarg;
1283 case ARG_LISTEN_RAW:
1284 if (arg_listen_raw) {
1285 log_error("cannot currently use --listen-raw more than once");
1289 arg_listen_raw = optarg;
1292 case ARG_LISTEN_HTTP:
1293 if (arg_listen_http || http_socket >= 0) {
1294 log_error("cannot currently use --listen-http more than once");
1298 r = negative_fd(optarg);
1302 arg_listen_http = optarg;
1305 case ARG_LISTEN_HTTPS:
1306 if (arg_listen_https || https_socket >= 0) {
1307 log_error("cannot currently use --listen-https more than once");
1311 r = negative_fd(optarg);
1315 arg_listen_https = optarg;
1321 log_error("Key file specified twice");
1325 arg_key = strdup(optarg);
1333 log_error("Certificate file specified twice");
1337 arg_cert = strdup(optarg);
1344 if (arg_trust || arg_trust_all) {
1345 log_error("Confusing trusted CA configuration");
1349 if (streq(optarg, "all"))
1350 arg_trust_all = true;
1353 arg_trust = strdup(optarg);
1357 log_error("Option --trust is not available.");
1366 log_error("cannot use --output/-o more than once");
1370 arg_output = optarg;
1373 case ARG_SPLIT_MODE:
1374 arg_split_mode = journal_write_split_mode_from_string(optarg);
1375 if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) {
1376 log_error("Invalid split mode: %s", optarg);
1383 r = parse_boolean(optarg);
1385 log_error("Failed to parse --compress= parameter.");
1391 arg_compress = true;
1397 r = parse_boolean(optarg);
1399 log_error("Failed to parse --seal= parameter.");
1409 case ARG_GNUTLS_LOG: {
1411 const char *word, *state;
1414 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
1417 cat = strndup(word, size);
1421 if (strv_consume(&arg_gnutls_log, cat) < 0)
1426 log_error("Option --gnutls-log is not available.");
1435 assert_not_reached("Unknown option code.");
1439 arg_files = argv + optind;
1441 type_a = arg_getter || !strv_isempty(arg_files);
1444 || arg_listen_http || arg_listen_https
1445 || sd_listen_fds(false) > 0;
1446 if (type_a && type_b) {
1447 log_error("Cannot use file input or --getter with "
1448 "--arg-listen-... or socket activation.");
1453 log_error("Option --output must be specified with file input or --getter.");
1457 arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
1460 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE
1461 && arg_output && is_dir(arg_output, true) > 0) {
1462 log_error("For SplitMode=none, output must be a file.");
1466 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
1467 && arg_output && is_dir(arg_output, true) <= 0) {
1468 log_error("For SplitMode=host, output must be a directory.");
1472 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1473 journal_write_split_mode_to_string(arg_split_mode),
1478 return 1 /* work to do */;
1481 static int load_certificates(char **key, char **cert, char **trust) {
1484 r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
1486 return log_error_errno(r, "Failed to read key from file '%s': %m",
1487 arg_key ?: PRIV_KEY_FILE);
1489 r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1491 return log_error_errno(r, "Failed to read certificate from file '%s': %m",
1492 arg_cert ?: CERT_FILE);
1495 log_info("Certificate checking disabled.");
1497 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1499 return log_error_errno(r, "Failed to read CA certificate file '%s': %m",
1500 arg_trust ?: TRUST_FILE);
1506 int main(int argc, char **argv) {
1507 RemoteServer s = {};
1509 _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1511 log_show_color(true);
1512 log_parse_environment();
1516 return EXIT_FAILURE;
1518 r = parse_argv(argc, argv);
1520 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1523 if (arg_listen_http || arg_listen_https) {
1524 r = setup_gnutls_logger(arg_gnutls_log);
1526 return EXIT_FAILURE;
1529 if (arg_listen_https || https_socket >= 0)
1530 if (load_certificates(&key, &cert, &trust) < 0)
1531 return EXIT_FAILURE;
1533 if (remoteserver_init(&s, key, cert, trust) < 0)
1534 return EXIT_FAILURE;
1536 r = sd_event_set_watchdog(s.events, true);
1538 log_error_errno(r, "Failed to enable watchdog: %m");
1540 log_debug("Watchdog is %s.", r > 0 ? "enabled" : "disabled");
1542 log_debug("%s running as pid "PID_FMT,
1543 program_invocation_short_name, getpid());
1546 "STATUS=Processing requests...");
1549 r = sd_event_get_state(s.events);
1552 if (r == SD_EVENT_FINISHED)
1555 r = sd_event_run(s.events, -1);
1557 log_error_errno(r, "Failed to run event loop: %m");
1564 "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
1565 log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
1573 return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;