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>
30 #include <sys/types.h>
34 #include "sd-daemon.h"
35 #include "journal-file.h"
36 #include "journald-native.h"
37 #include "socket-util.h"
43 #include "conf-parser.h"
44 #include "siphash24.h"
47 #include <gnutls/gnutls.h>
50 #include "journal-remote.h"
51 #include "journal-remote-write.h"
53 #define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
55 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
56 #define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
57 #define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
59 static char* arg_url = NULL;
60 static char* arg_getter = NULL;
61 static char* arg_listen_raw = NULL;
62 static char* arg_listen_http = NULL;
63 static char* arg_listen_https = NULL;
64 static char** arg_files = NULL;
65 static int arg_compress = true;
66 static int arg_seal = false;
67 static int http_socket = -1, https_socket = -1;
68 static char** arg_gnutls_log = NULL;
70 static JournalWriteSplitMode arg_split_mode = JOURNAL_WRITE_SPLIT_HOST;
71 static char* arg_output = NULL;
73 static char *arg_key = NULL;
74 static char *arg_cert = NULL;
75 static char *arg_trust = NULL;
76 static bool arg_trust_all = false;
78 /**********************************************************************
79 **********************************************************************
80 **********************************************************************/
82 static int spawn_child(const char* child, char** argv) {
84 pid_t parent_pid, child_pid;
88 return log_error_errno(errno, "Failed to create pager pipe: %m");
90 parent_pid = getpid();
95 log_error_errno(errno, "Failed to fork: %m");
101 if (child_pid == 0) {
102 r = dup2(fd[1], STDOUT_FILENO);
104 log_error_errno(errno, "Failed to dup pipe to stdout: %m");
110 /* Make sure the child goes away when the parent dies */
111 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
114 /* Check whether our parent died before we were able
115 * to set the death signal */
116 if (getppid() != parent_pid)
120 log_error_errno(errno, "Failed to exec child %s: %m", child);
126 log_warning_errno(errno, "Failed to close write end of pipe: %m");
131 static int spawn_curl(const char* url) {
132 char **argv = STRV_MAKE("curl",
133 "-HAccept: application/vnd.fdo.journal",
139 r = spawn_child("curl", argv);
141 log_error_errno(errno, "Failed to spawn curl: %m");
145 static int spawn_getter(const char *getter, const char *url) {
147 _cleanup_strv_free_ char **words = NULL;
150 r = strv_split_quoted(&words, getter, false);
152 return log_error_errno(r, "Failed to split getter option: %m");
154 r = strv_extend(&words, url);
156 return log_error_errno(r, "Failed to create command line: %m");
158 r = spawn_child(words[0], words);
160 log_error_errno(errno, "Failed to spawn getter %s: %m", getter);
165 #define filename_escape(s) xescape((s), "/ ")
167 static int open_output(Writer *w, const char* host) {
168 _cleanup_free_ char *_output = NULL;
172 switch (arg_split_mode) {
173 case JOURNAL_WRITE_SPLIT_NONE:
174 output = arg_output ?: REMOTE_JOURNAL_PATH "/remote.journal";
177 case JOURNAL_WRITE_SPLIT_HOST: {
178 _cleanup_free_ char *name;
182 name = filename_escape(host);
186 r = asprintf(&_output, "%s/remote-%s.journal",
187 arg_output ?: REMOTE_JOURNAL_PATH,
197 assert_not_reached("what?");
200 r = journal_file_open_reliably(output,
201 O_RDWR|O_CREAT, 0640,
202 arg_compress, arg_seal,
207 log_error_errno(r, "Failed to open output journal %s: %m",
210 log_info("Opened output file %s", w->journal->path);
214 /**********************************************************************
215 **********************************************************************
216 **********************************************************************/
218 static int init_writer_hashmap(RemoteServer *s) {
219 static const struct hash_ops *hash_ops[] = {
220 [JOURNAL_WRITE_SPLIT_NONE] = NULL,
221 [JOURNAL_WRITE_SPLIT_HOST] = &string_hash_ops,
224 assert(arg_split_mode >= 0 && arg_split_mode < (int) ELEMENTSOF(hash_ops));
226 s->writers = hashmap_new(hash_ops[arg_split_mode]);
233 static int get_writer(RemoteServer *s, const char *host,
236 _cleanup_writer_unref_ Writer *w = NULL;
239 switch(arg_split_mode) {
240 case JOURNAL_WRITE_SPLIT_NONE:
241 key = "one and only";
244 case JOURNAL_WRITE_SPLIT_HOST:
250 assert_not_reached("what split mode?");
253 w = hashmap_get(s->writers, key);
261 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST) {
262 w->hashmap_key = strdup(key);
267 r = open_output(w, host);
271 r = hashmap_put(s->writers, w->hashmap_key ?: key, w);
281 /**********************************************************************
282 **********************************************************************
283 **********************************************************************/
285 /* This should go away as soon as µhttpd allows state to be passed around. */
286 static RemoteServer *server;
288 static int dispatch_raw_source_event(sd_event_source *event,
292 static int dispatch_blocking_source_event(sd_event_source *event,
294 static int dispatch_raw_connection_event(sd_event_source *event,
298 static int dispatch_http_event(sd_event_source *event,
303 static int get_source_for_fd(RemoteServer *s,
304 int fd, char *name, RemoteSource **source) {
308 /* This takes ownership of name, but only on success. */
313 if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
316 r = get_writer(s, name, &writer);
318 return log_warning_errno(r, "Failed to get writer for source %s: %m",
321 if (s->sources[fd] == NULL) {
322 s->sources[fd] = source_new(fd, false, name, writer);
323 if (!s->sources[fd]) {
324 writer_unref(writer);
331 *source = s->sources[fd];
335 static int remove_source(RemoteServer *s, int fd) {
336 RemoteSource *source;
339 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
341 source = s->sources[fd];
343 /* this closes fd too */
345 s->sources[fd] = NULL;
352 static int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
354 RemoteSource *source;
357 /* This takes ownership of name, even on failure, if own_name is true. */
369 r = get_source_for_fd(s, fd, name, &source);
371 log_error_errno(r, "Failed to create source for fd:%d (%s): %m",
377 r = sd_event_add_io(s->events, &source->event,
378 fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
379 dispatch_raw_source_event, s);
381 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd, name);
382 r = sd_event_add_defer(s->events, &source->event,
383 dispatch_blocking_source_event, source);
385 sd_event_source_set_enabled(source->event, SD_EVENT_ON);
388 log_error_errno(r, "Failed to register event source for fd:%d: %m",
393 r = sd_event_source_set_description(source->event, name);
395 log_error_errno(r, "Failed to set source name for fd:%d: %m", fd);
399 return 1; /* work to do */
402 remove_source(s, fd);
406 static int add_raw_socket(RemoteServer *s, int fd) {
408 _cleanup_close_ int fd_ = fd;
409 char name[strlen("raw-socket-") + DECIMAL_STR_MAX(int)];
413 r = sd_event_add_io(s->events, &s->listen_event,
415 dispatch_raw_connection_event, s);
419 snprintf(name, sizeof(name), "raw-socket-%d", fd);
421 r = sd_event_source_set_description(s->listen_event, name);
430 static int setup_raw_socket(RemoteServer *s, const char *address) {
433 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
437 return add_raw_socket(s, fd);
440 /**********************************************************************
441 **********************************************************************
442 **********************************************************************/
444 static int request_meta(void **connection_cls, int fd, char *hostname) {
445 RemoteSource *source;
449 assert(connection_cls);
453 r = get_writer(server, hostname, &writer);
455 return log_warning_errno(r, "Failed to get writer for source %s: %m",
458 source = source_new(fd, true, hostname, writer);
460 writer_unref(writer);
464 log_debug("Added RemoteSource as connection metadata %p", source);
466 *connection_cls = source;
470 static void request_meta_free(void *cls,
471 struct MHD_Connection *connection,
472 void **connection_cls,
473 enum MHD_RequestTerminationCode toe) {
476 assert(connection_cls);
480 log_debug("Cleaning up connection metadata %p", s);
482 *connection_cls = NULL;
486 static int process_http_upload(
487 struct MHD_Connection *connection,
488 const char *upload_data,
489 size_t *upload_data_size,
490 RemoteSource *source) {
492 bool finished = false;
498 log_trace("%s: connection %p, %zu bytes",
499 __func__, connection, *upload_data_size);
501 if (*upload_data_size) {
502 log_trace("Received %zu bytes", *upload_data_size);
504 r = push_data(source, upload_data, *upload_data_size);
506 return mhd_respond_oom(connection);
508 *upload_data_size = 0;
513 r = process_source(source, arg_compress, arg_seal);
514 if (r == -EAGAIN || r == -EWOULDBLOCK)
517 log_warning("Failed to process data for connection %p", connection);
519 return mhd_respondf(connection,
520 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
521 "Entry is too large, maximum is %u bytes.\n",
524 return mhd_respondf(connection,
525 MHD_HTTP_UNPROCESSABLE_ENTITY,
526 "Processing failed: %s.", strerror(-r));
533 /* The upload is finished */
535 remaining = source_non_empty(source);
537 log_warning("Premature EOFbyte. %zu bytes lost.", remaining);
538 return mhd_respondf(connection, MHD_HTTP_EXPECTATION_FAILED,
539 "Premature EOF. %zu bytes of trailing data not processed.",
543 return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
546 static int request_handler(
548 struct MHD_Connection *connection,
552 const char *upload_data,
553 size_t *upload_data_size,
554 void **connection_cls) {
558 _cleanup_free_ char *hostname = NULL;
561 assert(connection_cls);
565 log_trace("Handling a connection %s %s %s", method, url, version);
568 return process_http_upload(connection,
569 upload_data, upload_data_size,
572 if (!streq(method, "POST"))
573 return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
574 "Unsupported method.\n");
576 if (!streq(url, "/upload"))
577 return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
580 header = MHD_lookup_connection_value(connection,
581 MHD_HEADER_KIND, "Content-Type");
582 if (!header || !streq(header, "application/vnd.fdo.journal"))
583 return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
584 "Content-Type: application/vnd.fdo.journal"
588 const union MHD_ConnectionInfo *ci;
590 ci = MHD_get_connection_info(connection,
591 MHD_CONNECTION_INFO_CONNECTION_FD);
593 log_error("MHD_get_connection_info failed: cannot get remote fd");
594 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
595 "Cannot check remote address");
602 if (server->check_trust) {
603 r = check_permissions(connection, &code, &hostname);
607 r = getnameinfo_pretty(fd, &hostname);
609 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
610 "Cannot check remote hostname");
616 r = request_meta(connection_cls, fd, hostname);
618 return respond_oom(connection);
620 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
627 static int setup_microhttpd_server(RemoteServer *s,
632 struct MHD_OptionItem opts[] = {
633 { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
634 { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
635 { MHD_OPTION_LISTEN_SOCKET, fd},
643 MHD_USE_PEDANTIC_CHECKS |
644 MHD_USE_EPOLL_LINUX_ONLY |
647 const union MHD_DaemonInfo *info;
653 r = fd_nonblock(fd, true);
655 return log_error_errno(r, "Failed to make fd:%d nonblocking: %m", fd);
660 opts[opts_pos++] = (struct MHD_OptionItem)
661 {MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
662 opts[opts_pos++] = (struct MHD_OptionItem)
663 {MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
665 flags |= MHD_USE_SSL;
668 opts[opts_pos++] = (struct MHD_OptionItem)
669 {MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
672 d = new(MHDDaemonWrapper, 1);
676 d->fd = (uint64_t) fd;
678 d->daemon = MHD_start_daemon(flags, 0,
680 request_handler, NULL,
681 MHD_OPTION_ARRAY, opts,
684 log_error("Failed to start µhttp daemon");
689 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
690 key ? "HTTPS" : "HTTP", fd, d);
693 info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
695 log_error("µhttp returned NULL daemon info");
700 epoll_fd = info->listen_fd;
702 log_error("µhttp epoll fd is invalid");
707 r = sd_event_add_io(s->events, &d->event,
709 dispatch_http_event, d);
711 log_error_errno(r, "Failed to add event callback: %m");
715 r = sd_event_source_set_description(d->event, "epoll-fd");
717 log_error_errno(r, "Failed to set source name: %m");
721 r = hashmap_ensure_allocated(&s->daemons, &uint64_hash_ops);
727 r = hashmap_put(s->daemons, &d->fd, d);
729 log_error_errno(r, "Failed to add daemon to hashmap: %m");
737 MHD_stop_daemon(d->daemon);
743 static int setup_microhttpd_socket(RemoteServer *s,
750 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
754 return setup_microhttpd_server(s, fd, key, cert, trust);
757 static int dispatch_http_event(sd_event_source *event,
761 MHDDaemonWrapper *d = userdata;
766 r = MHD_run(d->daemon);
768 log_error("MHD_run failed!");
769 // XXX: unregister daemon
773 return 1; /* work to do */
776 /**********************************************************************
777 **********************************************************************
778 **********************************************************************/
780 static int setup_signals(RemoteServer *s) {
786 assert_se(sigemptyset(&mask) == 0);
787 sigset_add_many(&mask, SIGINT, SIGTERM, -1);
788 assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
790 r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, NULL, s);
794 r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, NULL, s);
801 static int negative_fd(const char *spec) {
802 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
806 r = safe_atoi(spec, &fd);
816 static int remoteserver_init(RemoteServer *s,
825 if ((arg_listen_raw || arg_listen_http) && trust) {
826 log_error("Option --trust makes all non-HTTPS connections untrusted.");
830 r = sd_event_default(&s->events);
832 return log_error_errno(r, "Failed to allocate event loop: %m");
836 assert(server == NULL);
839 r = init_writer_hashmap(s);
843 n = sd_listen_fds(true);
845 return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
847 log_info("Received %d descriptors", n);
849 if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
850 log_error("Received fewer sockets than expected");
854 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
855 if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
856 log_info("Received a listening socket (fd:%d)", fd);
858 if (fd == http_socket)
859 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
860 else if (fd == https_socket)
861 r = setup_microhttpd_server(s, fd, key, cert, trust);
863 r = add_raw_socket(s, fd);
864 } else if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
867 r = getnameinfo_pretty(fd, &hostname);
869 return log_error_errno(r, "Failed to retrieve remote name: %m");
871 log_info("Received a connection socket (fd:%d) from %s", fd, hostname);
873 r = add_source(s, fd, hostname, true);
875 log_error("Unknown socket passed on fd:%d", fd);
881 return log_error_errno(r, "Failed to register socket (fd:%d): %m",
886 const char *url, *hostname;
888 url = strappenda(arg_url, "/entries");
891 log_info("Spawning getter %s...", url);
892 fd = spawn_getter(arg_getter, url);
894 log_info("Spawning curl %s...", url);
895 fd = spawn_curl(url);
901 startswith(arg_url, "https://") ?:
902 startswith(arg_url, "http://") ?:
905 r = add_source(s, fd, (char*) hostname, false);
910 if (arg_listen_raw) {
911 log_info("Listening on a socket...");
912 r = setup_raw_socket(s, arg_listen_raw);
917 if (arg_listen_http) {
918 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
923 if (arg_listen_https) {
924 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
929 STRV_FOREACH(file, arg_files) {
930 const char *output_name;
932 if (streq(*file, "-")) {
933 log_info("Using standard input as source.");
936 output_name = "stdin";
938 log_info("Reading file %s...", *file);
940 fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
942 return log_error_errno(errno, "Failed to open %s: %m", *file);
946 r = add_source(s, fd, (char*) output_name, false);
951 if (s->active == 0) {
952 log_error("Zarro sources specified");
956 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) {
957 /* In this case we know what the writer will be
958 called, so we can create it and verify that we can
959 create output as expected. */
960 r = get_writer(s, NULL, &s->_single_writer);
968 static void server_destroy(RemoteServer *s) {
972 while ((d = hashmap_steal_first(s->daemons))) {
973 MHD_stop_daemon(d->daemon);
974 sd_event_source_unref(d->event);
978 hashmap_free(s->daemons);
980 assert(s->sources_size == 0 || s->sources);
981 for (i = 0; i < s->sources_size; i++)
985 writer_unref(s->_single_writer);
986 hashmap_free(s->writers);
988 sd_event_source_unref(s->sigterm_event);
989 sd_event_source_unref(s->sigint_event);
990 sd_event_source_unref(s->listen_event);
991 sd_event_unref(s->events);
993 /* fds that we're listening on remain open... */
996 /**********************************************************************
997 **********************************************************************
998 **********************************************************************/
1000 static int dispatch_raw_source_event(sd_event_source *event,
1005 RemoteServer *s = userdata;
1006 RemoteSource *source;
1009 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
1010 source = s->sources[fd];
1011 assert(source->fd == fd);
1013 r = process_source(source, arg_compress, arg_seal);
1014 if (source->state == STATE_EOF) {
1017 log_info("EOF reached with source fd:%d (%s)",
1018 source->fd, source->name);
1020 remaining = source_non_empty(source);
1022 log_warning("Premature EOF. %zu bytes lost.", remaining);
1023 remove_source(s, source->fd);
1024 log_info("%zd active sources remaining", s->active);
1026 } else if (r == -E2BIG) {
1027 log_error("Entry too big, skipped");
1029 } else if (r == -EAGAIN) {
1032 log_info_errno(r, "Closing connection: %m");
1033 remove_source(server, fd);
1039 static int dispatch_blocking_source_event(sd_event_source *event,
1041 RemoteSource *source = userdata;
1043 return dispatch_raw_source_event(event, source->fd, EPOLLIN, server);
1046 static int accept_connection(const char* type, int fd,
1047 SocketAddress *addr, char **hostname) {
1050 log_debug("Accepting new %s connection on fd:%d", type, fd);
1051 fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
1053 return log_error_errno(errno, "accept() on fd:%d failed: %m", fd);
1055 switch(socket_address_family(addr)) {
1058 _cleanup_free_ char *a = NULL;
1061 r = socket_address_print(addr, &a);
1063 log_error_errno(r, "socket_address_print(): %m");
1068 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
1074 log_info("Accepted %s %s connection from %s",
1076 socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
1084 log_error("Rejected %s connection with unsupported family %d",
1085 type, socket_address_family(addr));
1092 static int dispatch_raw_connection_event(sd_event_source *event,
1096 RemoteServer *s = userdata;
1098 SocketAddress addr = {
1099 .size = sizeof(union sockaddr_union),
1100 .type = SOCK_STREAM,
1104 fd2 = accept_connection("raw", fd, &addr, &hostname);
1108 return add_source(s, fd2, hostname, true);
1111 /**********************************************************************
1112 **********************************************************************
1113 **********************************************************************/
1115 static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
1116 [JOURNAL_WRITE_SPLIT_NONE] = "none",
1117 [JOURNAL_WRITE_SPLIT_HOST] = "host",
1120 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
1121 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
1122 journal_write_split_mode,
1123 JournalWriteSplitMode,
1124 "Failed to parse split mode setting");
1126 static int parse_config(void) {
1127 const ConfigTableItem items[] = {
1128 { "Remote", "SplitMode", config_parse_write_split_mode, 0, &arg_split_mode },
1129 { "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key },
1130 { "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert },
1131 { "Remote", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
1134 return config_parse_many(PKGSYSCONFDIR "/journal-remote.conf",
1135 CONF_DIRS_NULSTR("systemd/journal-remote.conf"),
1136 "Remote\0", config_item_table_lookup, items,
1140 static void help(void) {
1141 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1142 "Write external journal events to journal file(s).\n\n"
1143 " -h --help Show this help\n"
1144 " --version Show package version\n"
1145 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1146 " --getter=COMMAND Read events from the output of COMMAND\n"
1147 " --listen-raw=ADDR Listen for connections at ADDR\n"
1148 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1149 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1150 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1151 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1152 " --seal[=BOOL] Use event sealing (default: no)\n"
1153 " --key=FILENAME SSL key in PEM format (default:\n"
1154 " \"" PRIV_KEY_FILE "\")\n"
1155 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1156 " \"" CERT_FILE "\")\n"
1157 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1158 " \"" TRUST_FILE "\")\n"
1159 " --gnutls-log=CATEGORY...\n"
1160 " Specify a list of gnutls logging categories\n"
1161 " --split-mode=none|host How many output files to create\n"
1163 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1164 , program_invocation_short_name);
1167 static int parse_argv(int argc, char *argv[]) {
1169 ARG_VERSION = 0x100,
1184 static const struct option options[] = {
1185 { "help", no_argument, NULL, 'h' },
1186 { "version", no_argument, NULL, ARG_VERSION },
1187 { "url", required_argument, NULL, ARG_URL },
1188 { "getter", required_argument, NULL, ARG_GETTER },
1189 { "listen-raw", required_argument, NULL, ARG_LISTEN_RAW },
1190 { "listen-http", required_argument, NULL, ARG_LISTEN_HTTP },
1191 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1192 { "output", required_argument, NULL, 'o' },
1193 { "split-mode", required_argument, NULL, ARG_SPLIT_MODE },
1194 { "compress", optional_argument, NULL, ARG_COMPRESS },
1195 { "seal", optional_argument, NULL, ARG_SEAL },
1196 { "key", required_argument, NULL, ARG_KEY },
1197 { "cert", required_argument, NULL, ARG_CERT },
1198 { "trust", required_argument, NULL, ARG_TRUST },
1199 { "gnutls-log", required_argument, NULL, ARG_GNUTLS_LOG },
1204 bool type_a, type_b;
1209 while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1213 return 0 /* done */;
1216 puts(PACKAGE_STRING);
1217 puts(SYSTEMD_FEATURES);
1218 return 0 /* done */;
1222 log_error("cannot currently set more than one --url");
1231 log_error("cannot currently use --getter more than once");
1235 arg_getter = optarg;
1238 case ARG_LISTEN_RAW:
1239 if (arg_listen_raw) {
1240 log_error("cannot currently use --listen-raw more than once");
1244 arg_listen_raw = optarg;
1247 case ARG_LISTEN_HTTP:
1248 if (arg_listen_http || http_socket >= 0) {
1249 log_error("cannot currently use --listen-http more than once");
1253 r = negative_fd(optarg);
1257 arg_listen_http = optarg;
1260 case ARG_LISTEN_HTTPS:
1261 if (arg_listen_https || https_socket >= 0) {
1262 log_error("cannot currently use --listen-https more than once");
1266 r = negative_fd(optarg);
1270 arg_listen_https = optarg;
1276 log_error("Key file specified twice");
1280 arg_key = strdup(optarg);
1288 log_error("Certificate file specified twice");
1292 arg_cert = strdup(optarg);
1299 if (arg_trust || arg_trust_all) {
1300 log_error("Confusing trusted CA configuration");
1304 if (streq(optarg, "all"))
1305 arg_trust_all = true;
1308 arg_trust = strdup(optarg);
1312 log_error("Option --trust is not available.");
1321 log_error("cannot use --output/-o more than once");
1325 arg_output = optarg;
1328 case ARG_SPLIT_MODE:
1329 arg_split_mode = journal_write_split_mode_from_string(optarg);
1330 if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) {
1331 log_error("Invalid split mode: %s", optarg);
1338 r = parse_boolean(optarg);
1340 log_error("Failed to parse --compress= parameter.");
1346 arg_compress = true;
1352 r = parse_boolean(optarg);
1354 log_error("Failed to parse --seal= parameter.");
1364 case ARG_GNUTLS_LOG: {
1366 const char *word, *state;
1369 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
1372 cat = strndup(word, size);
1376 if (strv_consume(&arg_gnutls_log, cat) < 0)
1381 log_error("Option --gnutls-log is not available.");
1390 assert_not_reached("Unknown option code.");
1394 arg_files = argv + optind;
1396 type_a = arg_getter || !strv_isempty(arg_files);
1399 || arg_listen_http || arg_listen_https
1400 || sd_listen_fds(false) > 0;
1401 if (type_a && type_b) {
1402 log_error("Cannot use file input or --getter with "
1403 "--arg-listen-... or socket activation.");
1408 log_error("Option --output must be specified with file input or --getter.");
1412 arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
1415 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE
1416 && arg_output && is_dir(arg_output, true) > 0) {
1417 log_error("For SplitMode=none, output must be a file.");
1421 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
1422 && arg_output && is_dir(arg_output, true) <= 0) {
1423 log_error("For SplitMode=host, output must be a directory.");
1427 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1428 journal_write_split_mode_to_string(arg_split_mode),
1433 return 1 /* work to do */;
1436 static int load_certificates(char **key, char **cert, char **trust) {
1439 r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
1441 return log_error_errno(r, "Failed to read key from file '%s': %m",
1442 arg_key ?: PRIV_KEY_FILE);
1444 r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1446 return log_error_errno(r, "Failed to read certificate from file '%s': %m",
1447 arg_cert ?: CERT_FILE);
1450 log_info("Certificate checking disabled.");
1452 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1454 return log_error_errno(r, "Failed to read CA certificate file '%s': %m",
1455 arg_trust ?: TRUST_FILE);
1461 static int setup_gnutls_logger(char **categories) {
1462 if (!arg_listen_http && !arg_listen_https)
1470 gnutls_global_set_log_function(log_func_gnutls);
1473 STRV_FOREACH(cat, categories) {
1474 r = log_enable_gnutls_category(*cat);
1479 log_reset_gnutls_level();
1486 int main(int argc, char **argv) {
1487 RemoteServer s = {};
1489 _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1491 log_show_color(true);
1492 log_parse_environment();
1496 return EXIT_FAILURE;
1498 r = parse_argv(argc, argv);
1500 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1502 r = setup_gnutls_logger(arg_gnutls_log);
1504 return EXIT_FAILURE;
1506 if (arg_listen_https || https_socket >= 0)
1507 if (load_certificates(&key, &cert, &trust) < 0)
1508 return EXIT_FAILURE;
1510 if (remoteserver_init(&s, key, cert, trust) < 0)
1511 return EXIT_FAILURE;
1513 r = sd_event_set_watchdog(s.events, true);
1515 log_error_errno(r, "Failed to enable watchdog: %m");
1517 log_debug("Watchdog is %s.", r > 0 ? "enabled" : "disabled");
1519 log_debug("%s running as pid "PID_FMT,
1520 program_invocation_short_name, getpid());
1523 "STATUS=Processing requests...");
1526 r = sd_event_get_state(s.events);
1529 if (r == SD_EVENT_FINISHED)
1532 r = sd_event_run(s.events, -1);
1534 log_error_errno(r, "Failed to run event loop: %m");
1541 "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
1542 log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
1550 return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;