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 log_error("Failed to create pager pipe: %m");
92 parent_pid = getpid();
97 log_error("Failed to fork: %m");
103 if (child_pid == 0) {
104 r = dup2(fd[1], STDOUT_FILENO);
106 log_error("Failed to dup pipe to stdout: %m");
112 /* Make sure the child goes away when the parent dies */
113 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
116 /* Check whether our parent died before we were able
117 * to set the death signal */
118 if (getppid() != parent_pid)
122 log_error("Failed to exec child %s: %m", child);
128 log_warning("Failed to close write end of pipe: %m");
133 static int spawn_curl(const char* url) {
134 char **argv = STRV_MAKE("curl",
135 "-HAccept: application/vnd.fdo.journal",
141 r = spawn_child("curl", argv);
143 log_error("Failed to spawn curl: %m");
147 static int spawn_getter(const char *getter, const char *url) {
149 _cleanup_strv_free_ char **words = NULL;
152 r = strv_split_quoted(&words, getter, false);
154 return log_error_errno(r, "Failed to split getter option: %m");
156 r = strv_extend(&words, url);
158 return log_error_errno(r, "Failed to create command line: %m");
160 r = spawn_child(words[0], words);
162 log_error("Failed to spawn getter %s: %m", getter);
167 #define filename_escape(s) xescape((s), "/ ")
169 static int open_output(Writer *w, const char* host) {
170 _cleanup_free_ char *_output = NULL;
174 switch (arg_split_mode) {
175 case JOURNAL_WRITE_SPLIT_NONE:
176 output = arg_output ?: REMOTE_JOURNAL_PATH "/remote.journal";
179 case JOURNAL_WRITE_SPLIT_HOST: {
180 _cleanup_free_ char *name;
184 name = filename_escape(host);
188 r = asprintf(&_output, "%s/remote-%s.journal",
189 arg_output ?: REMOTE_JOURNAL_PATH,
199 assert_not_reached("what?");
202 r = journal_file_open_reliably(output,
203 O_RDWR|O_CREAT, 0640,
204 arg_compress, arg_seal,
209 log_error_errno(r, "Failed to open output journal %s: %m",
212 log_info("Opened output file %s", w->journal->path);
216 /**********************************************************************
217 **********************************************************************
218 **********************************************************************/
220 static int init_writer_hashmap(RemoteServer *s) {
221 static const struct hash_ops *hash_ops[] = {
222 [JOURNAL_WRITE_SPLIT_NONE] = NULL,
223 [JOURNAL_WRITE_SPLIT_HOST] = &string_hash_ops,
226 assert(arg_split_mode >= 0 && arg_split_mode < (int) ELEMENTSOF(hash_ops));
228 s->writers = hashmap_new(hash_ops[arg_split_mode]);
235 static int get_writer(RemoteServer *s, const char *host,
238 _cleanup_writer_unref_ Writer *w = NULL;
241 switch(arg_split_mode) {
242 case JOURNAL_WRITE_SPLIT_NONE:
243 key = "one and only";
246 case JOURNAL_WRITE_SPLIT_HOST:
252 assert_not_reached("what split mode?");
255 w = hashmap_get(s->writers, key);
263 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST) {
264 w->hashmap_key = strdup(key);
269 r = open_output(w, host);
273 r = hashmap_put(s->writers, w->hashmap_key ?: key, w);
283 /**********************************************************************
284 **********************************************************************
285 **********************************************************************/
287 /* This should go away as soon as µhttpd allows state to be passed around. */
288 static RemoteServer *server;
290 static int dispatch_raw_source_event(sd_event_source *event,
294 static int dispatch_blocking_source_event(sd_event_source *event,
296 static int dispatch_raw_connection_event(sd_event_source *event,
300 static int dispatch_http_event(sd_event_source *event,
305 static int get_source_for_fd(RemoteServer *s,
306 int fd, char *name, RemoteSource **source) {
310 /* This takes ownership of name, but only on success. */
315 if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
318 r = get_writer(s, name, &writer);
320 return log_warning_errno(r, "Failed to get writer for source %s: %m",
323 if (s->sources[fd] == NULL) {
324 s->sources[fd] = source_new(fd, false, name, writer);
325 if (!s->sources[fd]) {
326 writer_unref(writer);
333 *source = s->sources[fd];
337 static int remove_source(RemoteServer *s, int fd) {
338 RemoteSource *source;
341 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
343 source = s->sources[fd];
345 /* this closes fd too */
347 s->sources[fd] = NULL;
354 static int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
356 RemoteSource *source;
359 /* This takes ownership of name, even on failure, if own_name is true. */
371 r = get_source_for_fd(s, fd, name, &source);
373 log_error_errno(r, "Failed to create source for fd:%d (%s): %m",
379 r = sd_event_add_io(s->events, &source->event,
380 fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
381 dispatch_raw_source_event, s);
383 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd, name);
384 r = sd_event_add_defer(s->events, &source->event,
385 dispatch_blocking_source_event, source);
387 sd_event_source_set_enabled(source->event, SD_EVENT_ON);
390 log_error_errno(r, "Failed to register event source for fd:%d: %m",
395 r = sd_event_source_set_description(source->event, name);
397 log_error_errno(r, "Failed to set source name for fd:%d: %m", fd);
401 return 1; /* work to do */
404 remove_source(s, fd);
408 static int add_raw_socket(RemoteServer *s, int fd) {
410 _cleanup_close_ int fd_ = fd;
411 char name[strlen("raw-socket-") + DECIMAL_STR_MAX(int)];
415 r = sd_event_add_io(s->events, &s->listen_event,
417 dispatch_raw_connection_event, s);
421 snprintf(name, sizeof(name), "raw-socket-%d", fd);
423 r = sd_event_source_set_description(s->listen_event, name);
432 static int setup_raw_socket(RemoteServer *s, const char *address) {
435 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
439 return add_raw_socket(s, fd);
442 /**********************************************************************
443 **********************************************************************
444 **********************************************************************/
446 static int request_meta(void **connection_cls, int fd, char *hostname) {
447 RemoteSource *source;
451 assert(connection_cls);
455 r = get_writer(server, hostname, &writer);
457 return log_warning_errno(r, "Failed to get writer for source %s: %m",
460 source = source_new(fd, true, hostname, writer);
462 writer_unref(writer);
466 log_debug("Added RemoteSource as connection metadata %p", source);
468 *connection_cls = source;
472 static void request_meta_free(void *cls,
473 struct MHD_Connection *connection,
474 void **connection_cls,
475 enum MHD_RequestTerminationCode toe) {
478 assert(connection_cls);
482 log_debug("Cleaning up connection metadata %p", s);
484 *connection_cls = NULL;
488 static int process_http_upload(
489 struct MHD_Connection *connection,
490 const char *upload_data,
491 size_t *upload_data_size,
492 RemoteSource *source) {
494 bool finished = false;
500 log_trace("%s: connection %p, %zu bytes",
501 __func__, connection, *upload_data_size);
503 if (*upload_data_size) {
504 log_trace("Received %zu bytes", *upload_data_size);
506 r = push_data(source, upload_data, *upload_data_size);
508 return mhd_respond_oom(connection);
510 *upload_data_size = 0;
515 r = process_source(source, arg_compress, arg_seal);
516 if (r == -EAGAIN || r == -EWOULDBLOCK)
519 log_warning("Failed to process data for connection %p", connection);
521 return mhd_respondf(connection,
522 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
523 "Entry is too large, maximum is %u bytes.\n",
526 return mhd_respondf(connection,
527 MHD_HTTP_UNPROCESSABLE_ENTITY,
528 "Processing failed: %s.", strerror(-r));
535 /* The upload is finished */
537 remaining = source_non_empty(source);
539 log_warning("Premature EOFbyte. %zu bytes lost.", remaining);
540 return mhd_respondf(connection, MHD_HTTP_EXPECTATION_FAILED,
541 "Premature EOF. %zu bytes of trailing data not processed.",
545 return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
548 static int request_handler(
550 struct MHD_Connection *connection,
554 const char *upload_data,
555 size_t *upload_data_size,
556 void **connection_cls) {
560 _cleanup_free_ char *hostname = NULL;
563 assert(connection_cls);
567 log_trace("Handling a connection %s %s %s", method, url, version);
570 return process_http_upload(connection,
571 upload_data, upload_data_size,
574 if (!streq(method, "POST"))
575 return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
576 "Unsupported method.\n");
578 if (!streq(url, "/upload"))
579 return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
582 header = MHD_lookup_connection_value(connection,
583 MHD_HEADER_KIND, "Content-Type");
584 if (!header || !streq(header, "application/vnd.fdo.journal"))
585 return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
586 "Content-Type: application/vnd.fdo.journal"
590 const union MHD_ConnectionInfo *ci;
592 ci = MHD_get_connection_info(connection,
593 MHD_CONNECTION_INFO_CONNECTION_FD);
595 log_error("MHD_get_connection_info failed: cannot get remote fd");
596 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
597 "Cannot check remote address");
604 if (server->check_trust) {
605 r = check_permissions(connection, &code, &hostname);
609 r = getnameinfo_pretty(fd, &hostname);
611 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
612 "Cannot check remote hostname");
618 r = request_meta(connection_cls, fd, hostname);
620 return respond_oom(connection);
622 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
629 static int setup_microhttpd_server(RemoteServer *s,
634 struct MHD_OptionItem opts[] = {
635 { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
636 { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
637 { MHD_OPTION_LISTEN_SOCKET, fd},
645 MHD_USE_PEDANTIC_CHECKS |
646 MHD_USE_EPOLL_LINUX_ONLY |
649 const union MHD_DaemonInfo *info;
655 r = fd_nonblock(fd, true);
657 return log_error_errno(r, "Failed to make fd:%d nonblocking: %m", fd);
662 opts[opts_pos++] = (struct MHD_OptionItem)
663 {MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
664 opts[opts_pos++] = (struct MHD_OptionItem)
665 {MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
667 flags |= MHD_USE_SSL;
670 opts[opts_pos++] = (struct MHD_OptionItem)
671 {MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
674 d = new(MHDDaemonWrapper, 1);
678 d->fd = (uint64_t) fd;
680 d->daemon = MHD_start_daemon(flags, 0,
682 request_handler, NULL,
683 MHD_OPTION_ARRAY, opts,
686 log_error("Failed to start µhttp daemon");
691 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
692 key ? "HTTPS" : "HTTP", fd, d);
695 info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
697 log_error("µhttp returned NULL daemon info");
702 epoll_fd = info->listen_fd;
704 log_error("µhttp epoll fd is invalid");
709 r = sd_event_add_io(s->events, &d->event,
711 dispatch_http_event, d);
713 log_error_errno(r, "Failed to add event callback: %m");
717 r = sd_event_source_set_description(d->event, "epoll-fd");
719 log_error_errno(r, "Failed to set source name: %m");
723 r = hashmap_ensure_allocated(&s->daemons, &uint64_hash_ops);
729 r = hashmap_put(s->daemons, &d->fd, d);
731 log_error_errno(r, "Failed to add daemon to hashmap: %m");
739 MHD_stop_daemon(d->daemon);
745 static int setup_microhttpd_socket(RemoteServer *s,
752 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
756 return setup_microhttpd_server(s, fd, key, cert, trust);
759 static int dispatch_http_event(sd_event_source *event,
763 MHDDaemonWrapper *d = userdata;
768 r = MHD_run(d->daemon);
770 log_error("MHD_run failed!");
771 // XXX: unregister daemon
775 return 1; /* work to do */
778 /**********************************************************************
779 **********************************************************************
780 **********************************************************************/
782 static int setup_signals(RemoteServer *s) {
788 assert_se(sigemptyset(&mask) == 0);
789 sigset_add_many(&mask, SIGINT, SIGTERM, -1);
790 assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
792 r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, NULL, s);
796 r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, NULL, s);
803 static int negative_fd(const char *spec) {
804 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
808 r = safe_atoi(spec, &fd);
818 static int remoteserver_init(RemoteServer *s,
827 if ((arg_listen_raw || arg_listen_http) && trust) {
828 log_error("Option --trust makes all non-HTTPS connections untrusted.");
832 r = sd_event_default(&s->events);
834 return log_error_errno(r, "Failed to allocate event loop: %m");
838 assert(server == NULL);
841 r = init_writer_hashmap(s);
845 n = sd_listen_fds(true);
847 return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
849 log_info("Received %d descriptors", n);
851 if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
852 log_error("Received fewer sockets than expected");
856 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
857 if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
858 log_info("Received a listening socket (fd:%d)", fd);
860 if (fd == http_socket)
861 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
862 else if (fd == https_socket)
863 r = setup_microhttpd_server(s, fd, key, cert, trust);
865 r = add_raw_socket(s, fd);
866 } else if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
869 r = getnameinfo_pretty(fd, &hostname);
871 return log_error_errno(r, "Failed to retrieve remote name: %m");
873 log_info("Received a connection socket (fd:%d) from %s", fd, hostname);
875 r = add_source(s, fd, hostname, true);
877 log_error("Unknown socket passed on fd:%d", fd);
883 return log_error_errno(r, "Failed to register socket (fd:%d): %m",
888 const char *url, *hostname;
890 url = strappenda(arg_url, "/entries");
893 log_info("Spawning getter %s...", url);
894 fd = spawn_getter(arg_getter, url);
896 log_info("Spawning curl %s...", url);
897 fd = spawn_curl(url);
903 startswith(arg_url, "https://") ?:
904 startswith(arg_url, "http://") ?:
907 r = add_source(s, fd, (char*) hostname, false);
912 if (arg_listen_raw) {
913 log_info("Listening on a socket...");
914 r = setup_raw_socket(s, arg_listen_raw);
919 if (arg_listen_http) {
920 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
925 if (arg_listen_https) {
926 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
931 STRV_FOREACH(file, arg_files) {
932 const char *output_name;
934 if (streq(*file, "-")) {
935 log_info("Using standard input as source.");
938 output_name = "stdin";
940 log_info("Reading file %s...", *file);
942 fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
944 log_error("Failed to open %s: %m", *file);
950 r = add_source(s, fd, (char*) output_name, false);
955 if (s->active == 0) {
956 log_error("Zarro sources specified");
960 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) {
961 /* In this case we know what the writer will be
962 called, so we can create it and verify that we can
963 create output as expected. */
964 r = get_writer(s, NULL, &s->_single_writer);
972 static void server_destroy(RemoteServer *s) {
976 while ((d = hashmap_steal_first(s->daemons))) {
977 MHD_stop_daemon(d->daemon);
978 sd_event_source_unref(d->event);
982 hashmap_free(s->daemons);
984 assert(s->sources_size == 0 || s->sources);
985 for (i = 0; i < s->sources_size; i++)
989 writer_unref(s->_single_writer);
990 hashmap_free(s->writers);
992 sd_event_source_unref(s->sigterm_event);
993 sd_event_source_unref(s->sigint_event);
994 sd_event_source_unref(s->listen_event);
995 sd_event_unref(s->events);
997 /* fds that we're listening on remain open... */
1000 /**********************************************************************
1001 **********************************************************************
1002 **********************************************************************/
1004 static int dispatch_raw_source_event(sd_event_source *event,
1009 RemoteServer *s = userdata;
1010 RemoteSource *source;
1013 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
1014 source = s->sources[fd];
1015 assert(source->fd == fd);
1017 r = process_source(source, arg_compress, arg_seal);
1018 if (source->state == STATE_EOF) {
1021 log_info("EOF reached with source fd:%d (%s)",
1022 source->fd, source->name);
1024 remaining = source_non_empty(source);
1026 log_warning("Premature EOF. %zu bytes lost.", remaining);
1027 remove_source(s, source->fd);
1028 log_info("%zd active sources remaining", s->active);
1030 } else if (r == -E2BIG) {
1031 log_error("Entry too big, skipped");
1033 } else if (r == -EAGAIN) {
1036 log_info_errno(r, "Closing connection: %m");
1037 remove_source(server, fd);
1043 static int dispatch_blocking_source_event(sd_event_source *event,
1045 RemoteSource *source = userdata;
1047 return dispatch_raw_source_event(event, source->fd, EPOLLIN, server);
1050 static int accept_connection(const char* type, int fd,
1051 SocketAddress *addr, char **hostname) {
1054 log_debug("Accepting new %s connection on fd:%d", type, fd);
1055 fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
1057 log_error("accept() on fd:%d failed: %m", fd);
1061 switch(socket_address_family(addr)) {
1064 _cleanup_free_ char *a = NULL;
1067 r = socket_address_print(addr, &a);
1069 log_error_errno(r, "socket_address_print(): %m");
1074 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
1080 log_info("Accepted %s %s connection from %s",
1082 socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
1090 log_error("Rejected %s connection with unsupported family %d",
1091 type, socket_address_family(addr));
1098 static int dispatch_raw_connection_event(sd_event_source *event,
1102 RemoteServer *s = userdata;
1104 SocketAddress addr = {
1105 .size = sizeof(union sockaddr_union),
1106 .type = SOCK_STREAM,
1110 fd2 = accept_connection("raw", fd, &addr, &hostname);
1114 return add_source(s, fd2, hostname, true);
1117 /**********************************************************************
1118 **********************************************************************
1119 **********************************************************************/
1121 static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
1122 [JOURNAL_WRITE_SPLIT_NONE] = "none",
1123 [JOURNAL_WRITE_SPLIT_HOST] = "host",
1126 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
1127 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
1128 journal_write_split_mode,
1129 JournalWriteSplitMode,
1130 "Failed to parse split mode setting");
1132 static int parse_config(void) {
1133 const ConfigTableItem items[] = {
1134 { "Remote", "SplitMode", config_parse_write_split_mode, 0, &arg_split_mode },
1135 { "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key },
1136 { "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert },
1137 { "Remote", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
1140 return config_parse(NULL, PKGSYSCONFDIR "/journal-remote.conf", NULL,
1142 config_item_table_lookup, items,
1143 false, false, true, NULL);
1146 static void help(void) {
1147 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1148 "Write external journal events to journal file(s).\n\n"
1149 " -h --help Show this help\n"
1150 " --version Show package version\n"
1151 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1152 " --getter=COMMAND Read events from the output of COMMAND\n"
1153 " --listen-raw=ADDR Listen for connections at ADDR\n"
1154 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1155 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1156 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1157 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1158 " --seal[=BOOL] Use event sealing (default: no)\n"
1159 " --key=FILENAME SSL key in PEM format (default:\n"
1160 " \"" PRIV_KEY_FILE "\")\n"
1161 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1162 " \"" CERT_FILE "\")\n"
1163 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1164 " \"" TRUST_FILE "\")\n"
1165 " --gnutls-log=CATEGORY...\n"
1166 " Specify a list of gnutls logging categories\n"
1167 " --split-mode=none|host How many output files to create\n"
1169 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1170 , program_invocation_short_name);
1173 static int parse_argv(int argc, char *argv[]) {
1175 ARG_VERSION = 0x100,
1190 static const struct option options[] = {
1191 { "help", no_argument, NULL, 'h' },
1192 { "version", no_argument, NULL, ARG_VERSION },
1193 { "url", required_argument, NULL, ARG_URL },
1194 { "getter", required_argument, NULL, ARG_GETTER },
1195 { "listen-raw", required_argument, NULL, ARG_LISTEN_RAW },
1196 { "listen-http", required_argument, NULL, ARG_LISTEN_HTTP },
1197 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1198 { "output", required_argument, NULL, 'o' },
1199 { "split-mode", required_argument, NULL, ARG_SPLIT_MODE },
1200 { "compress", optional_argument, NULL, ARG_COMPRESS },
1201 { "seal", optional_argument, NULL, ARG_SEAL },
1202 { "key", required_argument, NULL, ARG_KEY },
1203 { "cert", required_argument, NULL, ARG_CERT },
1204 { "trust", required_argument, NULL, ARG_TRUST },
1205 { "gnutls-log", required_argument, NULL, ARG_GNUTLS_LOG },
1210 bool type_a, type_b;
1215 while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1219 return 0 /* done */;
1222 puts(PACKAGE_STRING);
1223 puts(SYSTEMD_FEATURES);
1224 return 0 /* done */;
1228 log_error("cannot currently set more than one --url");
1237 log_error("cannot currently use --getter more than once");
1241 arg_getter = optarg;
1244 case ARG_LISTEN_RAW:
1245 if (arg_listen_raw) {
1246 log_error("cannot currently use --listen-raw more than once");
1250 arg_listen_raw = optarg;
1253 case ARG_LISTEN_HTTP:
1254 if (arg_listen_http || http_socket >= 0) {
1255 log_error("cannot currently use --listen-http more than once");
1259 r = negative_fd(optarg);
1263 arg_listen_http = optarg;
1266 case ARG_LISTEN_HTTPS:
1267 if (arg_listen_https || https_socket >= 0) {
1268 log_error("cannot currently use --listen-https more than once");
1272 r = negative_fd(optarg);
1276 arg_listen_https = optarg;
1282 log_error("Key file specified twice");
1286 arg_key = strdup(optarg);
1294 log_error("Certificate file specified twice");
1298 arg_cert = strdup(optarg);
1305 if (arg_trust || arg_trust_all) {
1306 log_error("Confusing trusted CA configuration");
1310 if (streq(optarg, "all"))
1311 arg_trust_all = true;
1314 arg_trust = strdup(optarg);
1318 log_error("Option --trust is not available.");
1327 log_error("cannot use --output/-o more than once");
1331 arg_output = optarg;
1334 case ARG_SPLIT_MODE:
1335 arg_split_mode = journal_write_split_mode_from_string(optarg);
1336 if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) {
1337 log_error("Invalid split mode: %s", optarg);
1344 r = parse_boolean(optarg);
1346 log_error("Failed to parse --compress= parameter.");
1352 arg_compress = true;
1358 r = parse_boolean(optarg);
1360 log_error("Failed to parse --seal= parameter.");
1370 case ARG_GNUTLS_LOG: {
1372 const char *word, *state;
1375 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
1378 cat = strndup(word, size);
1382 if (strv_consume(&arg_gnutls_log, cat) < 0)
1387 log_error("Option --gnutls-log is not available.");
1396 assert_not_reached("Unknown option code.");
1400 arg_files = argv + optind;
1402 type_a = arg_getter || !strv_isempty(arg_files);
1405 || arg_listen_http || arg_listen_https
1406 || sd_listen_fds(false) > 0;
1407 if (type_a && type_b) {
1408 log_error("Cannot use file input or --getter with "
1409 "--arg-listen-... or socket activation.");
1414 log_error("Option --output must be specified with file input or --getter.");
1418 arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
1421 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE
1422 && arg_output && is_dir(arg_output, true) > 0) {
1423 log_error("For SplitMode=none, output must be a file.");
1427 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
1428 && arg_output && is_dir(arg_output, true) <= 0) {
1429 log_error("For SplitMode=host, output must be a directory.");
1433 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1434 journal_write_split_mode_to_string(arg_split_mode),
1439 return 1 /* work to do */;
1442 static int load_certificates(char **key, char **cert, char **trust) {
1445 r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
1447 return log_error_errno(r, "Failed to read key from file '%s': %m",
1448 arg_key ?: PRIV_KEY_FILE);
1450 r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1452 return log_error_errno(r, "Failed to read certificate from file '%s': %m",
1453 arg_cert ?: CERT_FILE);
1456 log_info("Certificate checking disabled.");
1458 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1460 return log_error_errno(r, "Failed to read CA certificate file '%s': %m",
1461 arg_trust ?: TRUST_FILE);
1467 static int setup_gnutls_logger(char **categories) {
1468 if (!arg_listen_http && !arg_listen_https)
1476 gnutls_global_set_log_function(log_func_gnutls);
1479 STRV_FOREACH(cat, categories) {
1480 r = log_enable_gnutls_category(*cat);
1485 log_reset_gnutls_level();
1492 int main(int argc, char **argv) {
1493 RemoteServer s = {};
1495 _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1497 log_show_color(true);
1498 log_parse_environment();
1502 return EXIT_FAILURE;
1504 r = parse_argv(argc, argv);
1506 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1508 r = setup_gnutls_logger(arg_gnutls_log);
1510 return EXIT_FAILURE;
1512 if (arg_listen_https || https_socket >= 0)
1513 if (load_certificates(&key, &cert, &trust) < 0)
1514 return EXIT_FAILURE;
1516 if (remoteserver_init(&s, key, cert, trust) < 0)
1517 return EXIT_FAILURE;
1519 r = sd_event_set_watchdog(s.events, true);
1521 log_error_errno(r, "Failed to enable watchdog: %m");
1523 log_debug("Watchdog is %s.", r > 0 ? "enabled" : "disabled");
1525 log_debug("%s running as pid "PID_FMT,
1526 program_invocation_short_name, getpid());
1529 "STATUS=Processing requests...");
1532 r = sd_event_get_state(s.events);
1535 if (r == SD_EVENT_FINISHED)
1538 r = sd_event_run(s.events, -1);
1540 log_error_errno(r, "Failed to run event loop: %m");
1547 "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
1548 log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
1556 return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;