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 log_error_errno(r, "Failed to split getter option: %m");
158 r = strv_extend(&words, url);
160 log_error_errno(r, "Failed to create command line: %m");
164 r = spawn_child(words[0], words);
166 log_error("Failed to spawn getter %s: %m", getter);
171 #define filename_escape(s) xescape((s), "/ ")
173 static int open_output(Writer *w, const char* host) {
174 _cleanup_free_ char *_output = NULL;
178 switch (arg_split_mode) {
179 case JOURNAL_WRITE_SPLIT_NONE:
180 output = arg_output ?: REMOTE_JOURNAL_PATH "/remote.journal";
183 case JOURNAL_WRITE_SPLIT_HOST: {
184 _cleanup_free_ char *name;
188 name = filename_escape(host);
192 r = asprintf(&_output, "%s/remote-%s.journal",
193 arg_output ?: REMOTE_JOURNAL_PATH,
203 assert_not_reached("what?");
206 r = journal_file_open_reliably(output,
207 O_RDWR|O_CREAT, 0640,
208 arg_compress, arg_seal,
213 log_error_errno(r, "Failed to open output journal %s: %m",
216 log_info("Opened output file %s", w->journal->path);
220 /**********************************************************************
221 **********************************************************************
222 **********************************************************************/
224 static int init_writer_hashmap(RemoteServer *s) {
225 static const struct hash_ops *hash_ops[] = {
226 [JOURNAL_WRITE_SPLIT_NONE] = NULL,
227 [JOURNAL_WRITE_SPLIT_HOST] = &string_hash_ops,
230 assert(arg_split_mode >= 0 && arg_split_mode < (int) ELEMENTSOF(hash_ops));
232 s->writers = hashmap_new(hash_ops[arg_split_mode]);
239 static int get_writer(RemoteServer *s, const char *host,
242 _cleanup_writer_unref_ Writer *w = NULL;
245 switch(arg_split_mode) {
246 case JOURNAL_WRITE_SPLIT_NONE:
247 key = "one and only";
250 case JOURNAL_WRITE_SPLIT_HOST:
256 assert_not_reached("what split mode?");
259 w = hashmap_get(s->writers, key);
267 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST) {
268 w->hashmap_key = strdup(key);
273 r = open_output(w, host);
277 r = hashmap_put(s->writers, w->hashmap_key ?: key, w);
287 /**********************************************************************
288 **********************************************************************
289 **********************************************************************/
291 /* This should go away as soon as µhttpd allows state to be passed around. */
292 static RemoteServer *server;
294 static int dispatch_raw_source_event(sd_event_source *event,
298 static int dispatch_blocking_source_event(sd_event_source *event,
300 static int dispatch_raw_connection_event(sd_event_source *event,
304 static int dispatch_http_event(sd_event_source *event,
309 static int get_source_for_fd(RemoteServer *s,
310 int fd, char *name, RemoteSource **source) {
314 /* This takes ownership of name, but only on success. */
319 if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
322 r = get_writer(s, name, &writer);
324 log_warning_errno(r, "Failed to get writer for source %s: %m",
329 if (s->sources[fd] == NULL) {
330 s->sources[fd] = source_new(fd, false, name, writer);
331 if (!s->sources[fd]) {
332 writer_unref(writer);
339 *source = s->sources[fd];
343 static int remove_source(RemoteServer *s, int fd) {
344 RemoteSource *source;
347 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
349 source = s->sources[fd];
351 /* this closes fd too */
353 s->sources[fd] = NULL;
360 static int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
362 RemoteSource *source;
365 /* This takes ownership of name, even on failure, if own_name is true. */
377 r = get_source_for_fd(s, fd, name, &source);
379 log_error_errno(r, "Failed to create source for fd:%d (%s): %m",
385 r = sd_event_add_io(s->events, &source->event,
386 fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
387 dispatch_raw_source_event, s);
389 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd, name);
390 r = sd_event_add_defer(s->events, &source->event,
391 dispatch_blocking_source_event, source);
393 sd_event_source_set_enabled(source->event, SD_EVENT_ON);
396 log_error_errno(r, "Failed to register event source for fd:%d: %m",
401 r = sd_event_source_set_description(source->event, name);
403 log_error_errno(r, "Failed to set source name for fd:%d: %m", fd);
407 return 1; /* work to do */
410 remove_source(s, fd);
414 static int add_raw_socket(RemoteServer *s, int fd) {
416 _cleanup_close_ int fd_ = fd;
417 char name[strlen("raw-socket-") + DECIMAL_STR_MAX(int)];
421 r = sd_event_add_io(s->events, &s->listen_event,
423 dispatch_raw_connection_event, s);
427 snprintf(name, sizeof(name), "raw-socket-%d", fd);
429 r = sd_event_source_set_description(s->listen_event, name);
438 static int setup_raw_socket(RemoteServer *s, const char *address) {
441 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
445 return add_raw_socket(s, fd);
448 /**********************************************************************
449 **********************************************************************
450 **********************************************************************/
452 static int request_meta(void **connection_cls, int fd, char *hostname) {
453 RemoteSource *source;
457 assert(connection_cls);
461 r = get_writer(server, hostname, &writer);
463 log_warning_errno(r, "Failed to get writer for source %s: %m",
468 source = source_new(fd, true, hostname, writer);
470 writer_unref(writer);
474 log_debug("Added RemoteSource as connection metadata %p", source);
476 *connection_cls = source;
480 static void request_meta_free(void *cls,
481 struct MHD_Connection *connection,
482 void **connection_cls,
483 enum MHD_RequestTerminationCode toe) {
486 assert(connection_cls);
490 log_debug("Cleaning up connection metadata %p", s);
492 *connection_cls = NULL;
496 static int process_http_upload(
497 struct MHD_Connection *connection,
498 const char *upload_data,
499 size_t *upload_data_size,
500 RemoteSource *source) {
502 bool finished = false;
508 log_trace("%s: connection %p, %zu bytes",
509 __func__, connection, *upload_data_size);
511 if (*upload_data_size) {
512 log_trace("Received %zu bytes", *upload_data_size);
514 r = push_data(source, upload_data, *upload_data_size);
516 return mhd_respond_oom(connection);
518 *upload_data_size = 0;
523 r = process_source(source, arg_compress, arg_seal);
524 if (r == -EAGAIN || r == -EWOULDBLOCK)
527 log_warning("Failed to process data for connection %p", connection);
529 return mhd_respondf(connection,
530 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
531 "Entry is too large, maximum is %u bytes.\n",
534 return mhd_respondf(connection,
535 MHD_HTTP_UNPROCESSABLE_ENTITY,
536 "Processing failed: %s.", strerror(-r));
543 /* The upload is finished */
545 remaining = source_non_empty(source);
547 log_warning("Premature EOFbyte. %zu bytes lost.", remaining);
548 return mhd_respondf(connection, MHD_HTTP_EXPECTATION_FAILED,
549 "Premature EOF. %zu bytes of trailing data not processed.",
553 return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
556 static int request_handler(
558 struct MHD_Connection *connection,
562 const char *upload_data,
563 size_t *upload_data_size,
564 void **connection_cls) {
568 _cleanup_free_ char *hostname = NULL;
571 assert(connection_cls);
575 log_trace("Handling a connection %s %s %s", method, url, version);
578 return process_http_upload(connection,
579 upload_data, upload_data_size,
582 if (!streq(method, "POST"))
583 return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
584 "Unsupported method.\n");
586 if (!streq(url, "/upload"))
587 return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
590 header = MHD_lookup_connection_value(connection,
591 MHD_HEADER_KIND, "Content-Type");
592 if (!header || !streq(header, "application/vnd.fdo.journal"))
593 return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
594 "Content-Type: application/vnd.fdo.journal"
598 const union MHD_ConnectionInfo *ci;
600 ci = MHD_get_connection_info(connection,
601 MHD_CONNECTION_INFO_CONNECTION_FD);
603 log_error("MHD_get_connection_info failed: cannot get remote fd");
604 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
605 "Cannot check remote address");
612 if (server->check_trust) {
613 r = check_permissions(connection, &code, &hostname);
617 r = getnameinfo_pretty(fd, &hostname);
619 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
620 "Cannot check remote hostname");
626 r = request_meta(connection_cls, fd, hostname);
628 return respond_oom(connection);
630 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
637 static int setup_microhttpd_server(RemoteServer *s,
642 struct MHD_OptionItem opts[] = {
643 { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
644 { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
645 { MHD_OPTION_LISTEN_SOCKET, fd},
653 MHD_USE_PEDANTIC_CHECKS |
654 MHD_USE_EPOLL_LINUX_ONLY |
657 const union MHD_DaemonInfo *info;
663 r = fd_nonblock(fd, true);
665 log_error_errno(r, "Failed to make fd:%d nonblocking: %m", fd);
672 opts[opts_pos++] = (struct MHD_OptionItem)
673 {MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
674 opts[opts_pos++] = (struct MHD_OptionItem)
675 {MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
677 flags |= MHD_USE_SSL;
680 opts[opts_pos++] = (struct MHD_OptionItem)
681 {MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
684 d = new(MHDDaemonWrapper, 1);
688 d->fd = (uint64_t) fd;
690 d->daemon = MHD_start_daemon(flags, 0,
692 request_handler, NULL,
693 MHD_OPTION_ARRAY, opts,
696 log_error("Failed to start µhttp daemon");
701 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
702 key ? "HTTPS" : "HTTP", fd, d);
705 info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
707 log_error("µhttp returned NULL daemon info");
712 epoll_fd = info->listen_fd;
714 log_error("µhttp epoll fd is invalid");
719 r = sd_event_add_io(s->events, &d->event,
721 dispatch_http_event, d);
723 log_error_errno(r, "Failed to add event callback: %m");
727 r = sd_event_source_set_description(d->event, "epoll-fd");
729 log_error_errno(r, "Failed to set source name: %m");
733 r = hashmap_ensure_allocated(&s->daemons, &uint64_hash_ops);
739 r = hashmap_put(s->daemons, &d->fd, d);
741 log_error_errno(r, "Failed to add daemon to hashmap: %m");
749 MHD_stop_daemon(d->daemon);
755 static int setup_microhttpd_socket(RemoteServer *s,
762 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
766 return setup_microhttpd_server(s, fd, key, cert, trust);
769 static int dispatch_http_event(sd_event_source *event,
773 MHDDaemonWrapper *d = userdata;
778 r = MHD_run(d->daemon);
780 log_error("MHD_run failed!");
781 // XXX: unregister daemon
785 return 1; /* work to do */
788 /**********************************************************************
789 **********************************************************************
790 **********************************************************************/
792 static int setup_signals(RemoteServer *s) {
798 assert_se(sigemptyset(&mask) == 0);
799 sigset_add_many(&mask, SIGINT, SIGTERM, -1);
800 assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
802 r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, NULL, s);
806 r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, NULL, s);
813 static int negative_fd(const char *spec) {
814 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
818 r = safe_atoi(spec, &fd);
828 static int remoteserver_init(RemoteServer *s,
837 if ((arg_listen_raw || arg_listen_http) && trust) {
838 log_error("Option --trust makes all non-HTTPS connections untrusted.");
842 r = sd_event_default(&s->events);
844 log_error_errno(r, "Failed to allocate event loop: %m");
850 assert(server == NULL);
853 r = init_writer_hashmap(s);
857 n = sd_listen_fds(true);
859 log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
862 log_info("Received %d descriptors", n);
864 if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
865 log_error("Received fewer sockets than expected");
869 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
870 if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
871 log_info("Received a listening socket (fd:%d)", fd);
873 if (fd == http_socket)
874 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
875 else if (fd == https_socket)
876 r = setup_microhttpd_server(s, fd, key, cert, trust);
878 r = add_raw_socket(s, fd);
879 } else if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
882 r = getnameinfo_pretty(fd, &hostname);
884 log_error_errno(r, "Failed to retrieve remote name: %m");
888 log_info("Received a connection socket (fd:%d) from %s", fd, hostname);
890 r = add_source(s, fd, hostname, true);
892 log_error("Unknown socket passed on fd:%d", fd);
898 log_error_errno(r, "Failed to register socket (fd:%d): %m",
905 const char *url, *hostname;
907 url = strappenda(arg_url, "/entries");
910 log_info("Spawning getter %s...", url);
911 fd = spawn_getter(arg_getter, url);
913 log_info("Spawning curl %s...", url);
914 fd = spawn_curl(url);
920 startswith(arg_url, "https://") ?:
921 startswith(arg_url, "http://") ?:
924 r = add_source(s, fd, (char*) hostname, false);
929 if (arg_listen_raw) {
930 log_info("Listening on a socket...");
931 r = setup_raw_socket(s, arg_listen_raw);
936 if (arg_listen_http) {
937 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
942 if (arg_listen_https) {
943 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
948 STRV_FOREACH(file, arg_files) {
949 const char *output_name;
951 if (streq(*file, "-")) {
952 log_info("Using standard input as source.");
955 output_name = "stdin";
957 log_info("Reading file %s...", *file);
959 fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
961 log_error("Failed to open %s: %m", *file);
967 r = add_source(s, fd, (char*) output_name, false);
972 if (s->active == 0) {
973 log_error("Zarro sources specified");
977 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) {
978 /* In this case we know what the writer will be
979 called, so we can create it and verify that we can
980 create output as expected. */
981 r = get_writer(s, NULL, &s->_single_writer);
989 static void server_destroy(RemoteServer *s) {
993 while ((d = hashmap_steal_first(s->daemons))) {
994 MHD_stop_daemon(d->daemon);
995 sd_event_source_unref(d->event);
999 hashmap_free(s->daemons);
1001 assert(s->sources_size == 0 || s->sources);
1002 for (i = 0; i < s->sources_size; i++)
1003 remove_source(s, i);
1006 writer_unref(s->_single_writer);
1007 hashmap_free(s->writers);
1009 sd_event_source_unref(s->sigterm_event);
1010 sd_event_source_unref(s->sigint_event);
1011 sd_event_source_unref(s->listen_event);
1012 sd_event_unref(s->events);
1014 /* fds that we're listening on remain open... */
1017 /**********************************************************************
1018 **********************************************************************
1019 **********************************************************************/
1021 static int dispatch_raw_source_event(sd_event_source *event,
1026 RemoteServer *s = userdata;
1027 RemoteSource *source;
1030 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
1031 source = s->sources[fd];
1032 assert(source->fd == fd);
1034 r = process_source(source, arg_compress, arg_seal);
1035 if (source->state == STATE_EOF) {
1038 log_info("EOF reached with source fd:%d (%s)",
1039 source->fd, source->name);
1041 remaining = source_non_empty(source);
1043 log_warning("Premature EOF. %zu bytes lost.", remaining);
1044 remove_source(s, source->fd);
1045 log_info("%zd active sources remaining", s->active);
1047 } else if (r == -E2BIG) {
1048 log_error("Entry too big, skipped");
1050 } else if (r == -EAGAIN) {
1053 log_info_errno(r, "Closing connection: %m");
1054 remove_source(server, fd);
1060 static int dispatch_blocking_source_event(sd_event_source *event,
1062 RemoteSource *source = userdata;
1064 return dispatch_raw_source_event(event, source->fd, EPOLLIN, server);
1067 static int accept_connection(const char* type, int fd,
1068 SocketAddress *addr, char **hostname) {
1071 log_debug("Accepting new %s connection on fd:%d", type, fd);
1072 fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
1074 log_error("accept() on fd:%d failed: %m", fd);
1078 switch(socket_address_family(addr)) {
1081 _cleanup_free_ char *a = NULL;
1084 r = socket_address_print(addr, &a);
1086 log_error_errno(r, "socket_address_print(): %m");
1091 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
1097 log_info("Accepted %s %s connection from %s",
1099 socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
1107 log_error("Rejected %s connection with unsupported family %d",
1108 type, socket_address_family(addr));
1115 static int dispatch_raw_connection_event(sd_event_source *event,
1119 RemoteServer *s = userdata;
1121 SocketAddress addr = {
1122 .size = sizeof(union sockaddr_union),
1123 .type = SOCK_STREAM,
1127 fd2 = accept_connection("raw", fd, &addr, &hostname);
1131 return add_source(s, fd2, hostname, true);
1134 /**********************************************************************
1135 **********************************************************************
1136 **********************************************************************/
1138 static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
1139 [JOURNAL_WRITE_SPLIT_NONE] = "none",
1140 [JOURNAL_WRITE_SPLIT_HOST] = "host",
1143 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
1144 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
1145 journal_write_split_mode,
1146 JournalWriteSplitMode,
1147 "Failed to parse split mode setting");
1149 static int parse_config(void) {
1150 const ConfigTableItem items[] = {
1151 { "Remote", "SplitMode", config_parse_write_split_mode, 0, &arg_split_mode },
1152 { "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key },
1153 { "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert },
1154 { "Remote", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
1157 return config_parse(NULL, PKGSYSCONFDIR "/journal-remote.conf", NULL,
1159 config_item_table_lookup, items,
1160 false, false, true, NULL);
1163 static void help(void) {
1164 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1165 "Write external journal events to journal file(s).\n\n"
1166 " -h --help Show this help\n"
1167 " --version Show package version\n"
1168 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1169 " --getter=COMMAND Read events from the output of COMMAND\n"
1170 " --listen-raw=ADDR Listen for connections at ADDR\n"
1171 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1172 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1173 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1174 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1175 " --seal[=BOOL] Use event sealing (default: no)\n"
1176 " --key=FILENAME SSL key in PEM format (default:\n"
1177 " \"" PRIV_KEY_FILE "\")\n"
1178 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1179 " \"" CERT_FILE "\")\n"
1180 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1181 " \"" TRUST_FILE "\")\n"
1182 " --gnutls-log=CATEGORY...\n"
1183 " Specify a list of gnutls logging categories\n"
1184 " --split-mode=none|host How many output files to create\n"
1186 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1187 , program_invocation_short_name);
1190 static int parse_argv(int argc, char *argv[]) {
1192 ARG_VERSION = 0x100,
1207 static const struct option options[] = {
1208 { "help", no_argument, NULL, 'h' },
1209 { "version", no_argument, NULL, ARG_VERSION },
1210 { "url", required_argument, NULL, ARG_URL },
1211 { "getter", required_argument, NULL, ARG_GETTER },
1212 { "listen-raw", required_argument, NULL, ARG_LISTEN_RAW },
1213 { "listen-http", required_argument, NULL, ARG_LISTEN_HTTP },
1214 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1215 { "output", required_argument, NULL, 'o' },
1216 { "split-mode", required_argument, NULL, ARG_SPLIT_MODE },
1217 { "compress", optional_argument, NULL, ARG_COMPRESS },
1218 { "seal", optional_argument, NULL, ARG_SEAL },
1219 { "key", required_argument, NULL, ARG_KEY },
1220 { "cert", required_argument, NULL, ARG_CERT },
1221 { "trust", required_argument, NULL, ARG_TRUST },
1222 { "gnutls-log", required_argument, NULL, ARG_GNUTLS_LOG },
1227 bool type_a, type_b;
1232 while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1236 return 0 /* done */;
1239 puts(PACKAGE_STRING);
1240 puts(SYSTEMD_FEATURES);
1241 return 0 /* done */;
1245 log_error("cannot currently set more than one --url");
1254 log_error("cannot currently use --getter more than once");
1258 arg_getter = optarg;
1261 case ARG_LISTEN_RAW:
1262 if (arg_listen_raw) {
1263 log_error("cannot currently use --listen-raw more than once");
1267 arg_listen_raw = optarg;
1270 case ARG_LISTEN_HTTP:
1271 if (arg_listen_http || http_socket >= 0) {
1272 log_error("cannot currently use --listen-http more than once");
1276 r = negative_fd(optarg);
1280 arg_listen_http = optarg;
1283 case ARG_LISTEN_HTTPS:
1284 if (arg_listen_https || https_socket >= 0) {
1285 log_error("cannot currently use --listen-https more than once");
1289 r = negative_fd(optarg);
1293 arg_listen_https = optarg;
1299 log_error("Key file specified twice");
1303 arg_key = strdup(optarg);
1311 log_error("Certificate file specified twice");
1315 arg_cert = strdup(optarg);
1322 if (arg_trust || arg_trust_all) {
1323 log_error("Confusing trusted CA configuration");
1327 if (streq(optarg, "all"))
1328 arg_trust_all = true;
1331 arg_trust = strdup(optarg);
1335 log_error("Option --trust is not available.");
1344 log_error("cannot use --output/-o more than once");
1348 arg_output = optarg;
1351 case ARG_SPLIT_MODE:
1352 arg_split_mode = journal_write_split_mode_from_string(optarg);
1353 if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) {
1354 log_error("Invalid split mode: %s", optarg);
1361 r = parse_boolean(optarg);
1363 log_error("Failed to parse --compress= parameter.");
1369 arg_compress = true;
1375 r = parse_boolean(optarg);
1377 log_error("Failed to parse --seal= parameter.");
1387 case ARG_GNUTLS_LOG: {
1389 const char *word, *state;
1392 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
1395 cat = strndup(word, size);
1399 if (strv_consume(&arg_gnutls_log, cat) < 0)
1404 log_error("Option --gnutls-log is not available.");
1413 assert_not_reached("Unknown option code.");
1417 arg_files = argv + optind;
1419 type_a = arg_getter || !strv_isempty(arg_files);
1422 || arg_listen_http || arg_listen_https
1423 || sd_listen_fds(false) > 0;
1424 if (type_a && type_b) {
1425 log_error("Cannot use file input or --getter with "
1426 "--arg-listen-... or socket activation.");
1431 log_error("Option --output must be specified with file input or --getter.");
1435 arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
1438 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE
1439 && arg_output && is_dir(arg_output, true) > 0) {
1440 log_error("For SplitMode=none, output must be a file.");
1444 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
1445 && arg_output && is_dir(arg_output, true) <= 0) {
1446 log_error("For SplitMode=host, output must be a directory.");
1450 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1451 journal_write_split_mode_to_string(arg_split_mode),
1456 return 1 /* work to do */;
1459 static int load_certificates(char **key, char **cert, char **trust) {
1462 r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
1464 log_error_errno(r, "Failed to read key from file '%s': %m",
1465 arg_key ?: PRIV_KEY_FILE);
1469 r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1471 log_error_errno(r, "Failed to read certificate from file '%s': %m",
1472 arg_cert ?: CERT_FILE);
1477 log_info("Certificate checking disabled.");
1479 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1481 log_error_errno(r, "Failed to read CA certificate file '%s': %m",
1482 arg_trust ?: TRUST_FILE);
1490 static int setup_gnutls_logger(char **categories) {
1491 if (!arg_listen_http && !arg_listen_https)
1499 gnutls_global_set_log_function(log_func_gnutls);
1502 STRV_FOREACH(cat, categories) {
1503 r = log_enable_gnutls_category(*cat);
1508 log_reset_gnutls_level();
1515 int main(int argc, char **argv) {
1516 RemoteServer s = {};
1518 _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1520 log_show_color(true);
1521 log_parse_environment();
1525 return EXIT_FAILURE;
1527 r = parse_argv(argc, argv);
1529 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1531 r = setup_gnutls_logger(arg_gnutls_log);
1533 return EXIT_FAILURE;
1535 if (arg_listen_https || https_socket >= 0)
1536 if (load_certificates(&key, &cert, &trust) < 0)
1537 return EXIT_FAILURE;
1539 if (remoteserver_init(&s, key, cert, trust) < 0)
1540 return EXIT_FAILURE;
1542 r = sd_event_set_watchdog(s.events, true);
1544 log_error_errno(r, "Failed to enable watchdog: %m");
1546 log_debug("Watchdog is %s.", r > 0 ? "enabled" : "disabled");
1548 log_debug("%s running as pid "PID_FMT,
1549 program_invocation_short_name, getpid());
1552 "STATUS=Processing requests...");
1555 r = sd_event_get_state(s.events);
1558 if (r == SD_EVENT_FINISHED)
1561 r = sd_event_run(s.events, -1);
1563 log_error_errno(r, "Failed to run event loop: %m");
1570 "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
1571 log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
1579 return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;