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 return log_warning_errno(r, "Failed to get writer for source %s: %m",
327 if (s->sources[fd] == NULL) {
328 s->sources[fd] = source_new(fd, false, name, writer);
329 if (!s->sources[fd]) {
330 writer_unref(writer);
337 *source = s->sources[fd];
341 static int remove_source(RemoteServer *s, int fd) {
342 RemoteSource *source;
345 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
347 source = s->sources[fd];
349 /* this closes fd too */
351 s->sources[fd] = NULL;
358 static int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
360 RemoteSource *source;
363 /* This takes ownership of name, even on failure, if own_name is true. */
375 r = get_source_for_fd(s, fd, name, &source);
377 log_error_errno(r, "Failed to create source for fd:%d (%s): %m",
383 r = sd_event_add_io(s->events, &source->event,
384 fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
385 dispatch_raw_source_event, s);
387 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd, name);
388 r = sd_event_add_defer(s->events, &source->event,
389 dispatch_blocking_source_event, source);
391 sd_event_source_set_enabled(source->event, SD_EVENT_ON);
394 log_error_errno(r, "Failed to register event source for fd:%d: %m",
399 r = sd_event_source_set_description(source->event, name);
401 log_error_errno(r, "Failed to set source name for fd:%d: %m", fd);
405 return 1; /* work to do */
408 remove_source(s, fd);
412 static int add_raw_socket(RemoteServer *s, int fd) {
414 _cleanup_close_ int fd_ = fd;
415 char name[strlen("raw-socket-") + DECIMAL_STR_MAX(int)];
419 r = sd_event_add_io(s->events, &s->listen_event,
421 dispatch_raw_connection_event, s);
425 snprintf(name, sizeof(name), "raw-socket-%d", fd);
427 r = sd_event_source_set_description(s->listen_event, name);
436 static int setup_raw_socket(RemoteServer *s, const char *address) {
439 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
443 return add_raw_socket(s, fd);
446 /**********************************************************************
447 **********************************************************************
448 **********************************************************************/
450 static int request_meta(void **connection_cls, int fd, char *hostname) {
451 RemoteSource *source;
455 assert(connection_cls);
459 r = get_writer(server, hostname, &writer);
461 return log_warning_errno(r, "Failed to get writer for source %s: %m",
464 source = source_new(fd, true, hostname, writer);
466 writer_unref(writer);
470 log_debug("Added RemoteSource as connection metadata %p", source);
472 *connection_cls = source;
476 static void request_meta_free(void *cls,
477 struct MHD_Connection *connection,
478 void **connection_cls,
479 enum MHD_RequestTerminationCode toe) {
482 assert(connection_cls);
486 log_debug("Cleaning up connection metadata %p", s);
488 *connection_cls = NULL;
492 static int process_http_upload(
493 struct MHD_Connection *connection,
494 const char *upload_data,
495 size_t *upload_data_size,
496 RemoteSource *source) {
498 bool finished = false;
504 log_trace("%s: connection %p, %zu bytes",
505 __func__, connection, *upload_data_size);
507 if (*upload_data_size) {
508 log_trace("Received %zu bytes", *upload_data_size);
510 r = push_data(source, upload_data, *upload_data_size);
512 return mhd_respond_oom(connection);
514 *upload_data_size = 0;
519 r = process_source(source, arg_compress, arg_seal);
520 if (r == -EAGAIN || r == -EWOULDBLOCK)
523 log_warning("Failed to process data for connection %p", connection);
525 return mhd_respondf(connection,
526 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
527 "Entry is too large, maximum is %u bytes.\n",
530 return mhd_respondf(connection,
531 MHD_HTTP_UNPROCESSABLE_ENTITY,
532 "Processing failed: %s.", strerror(-r));
539 /* The upload is finished */
541 remaining = source_non_empty(source);
543 log_warning("Premature EOFbyte. %zu bytes lost.", remaining);
544 return mhd_respondf(connection, MHD_HTTP_EXPECTATION_FAILED,
545 "Premature EOF. %zu bytes of trailing data not processed.",
549 return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
552 static int request_handler(
554 struct MHD_Connection *connection,
558 const char *upload_data,
559 size_t *upload_data_size,
560 void **connection_cls) {
564 _cleanup_free_ char *hostname = NULL;
567 assert(connection_cls);
571 log_trace("Handling a connection %s %s %s", method, url, version);
574 return process_http_upload(connection,
575 upload_data, upload_data_size,
578 if (!streq(method, "POST"))
579 return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
580 "Unsupported method.\n");
582 if (!streq(url, "/upload"))
583 return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
586 header = MHD_lookup_connection_value(connection,
587 MHD_HEADER_KIND, "Content-Type");
588 if (!header || !streq(header, "application/vnd.fdo.journal"))
589 return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
590 "Content-Type: application/vnd.fdo.journal"
594 const union MHD_ConnectionInfo *ci;
596 ci = MHD_get_connection_info(connection,
597 MHD_CONNECTION_INFO_CONNECTION_FD);
599 log_error("MHD_get_connection_info failed: cannot get remote fd");
600 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
601 "Cannot check remote address");
608 if (server->check_trust) {
609 r = check_permissions(connection, &code, &hostname);
613 r = getnameinfo_pretty(fd, &hostname);
615 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
616 "Cannot check remote hostname");
622 r = request_meta(connection_cls, fd, hostname);
624 return respond_oom(connection);
626 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
633 static int setup_microhttpd_server(RemoteServer *s,
638 struct MHD_OptionItem opts[] = {
639 { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
640 { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
641 { MHD_OPTION_LISTEN_SOCKET, fd},
649 MHD_USE_PEDANTIC_CHECKS |
650 MHD_USE_EPOLL_LINUX_ONLY |
653 const union MHD_DaemonInfo *info;
659 r = fd_nonblock(fd, true);
661 log_error_errno(r, "Failed to make fd:%d nonblocking: %m", fd);
668 opts[opts_pos++] = (struct MHD_OptionItem)
669 {MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
670 opts[opts_pos++] = (struct MHD_OptionItem)
671 {MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
673 flags |= MHD_USE_SSL;
676 opts[opts_pos++] = (struct MHD_OptionItem)
677 {MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
680 d = new(MHDDaemonWrapper, 1);
684 d->fd = (uint64_t) fd;
686 d->daemon = MHD_start_daemon(flags, 0,
688 request_handler, NULL,
689 MHD_OPTION_ARRAY, opts,
692 log_error("Failed to start µhttp daemon");
697 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
698 key ? "HTTPS" : "HTTP", fd, d);
701 info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
703 log_error("µhttp returned NULL daemon info");
708 epoll_fd = info->listen_fd;
710 log_error("µhttp epoll fd is invalid");
715 r = sd_event_add_io(s->events, &d->event,
717 dispatch_http_event, d);
719 log_error_errno(r, "Failed to add event callback: %m");
723 r = sd_event_source_set_description(d->event, "epoll-fd");
725 log_error_errno(r, "Failed to set source name: %m");
729 r = hashmap_ensure_allocated(&s->daemons, &uint64_hash_ops);
735 r = hashmap_put(s->daemons, &d->fd, d);
737 log_error_errno(r, "Failed to add daemon to hashmap: %m");
745 MHD_stop_daemon(d->daemon);
751 static int setup_microhttpd_socket(RemoteServer *s,
758 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
762 return setup_microhttpd_server(s, fd, key, cert, trust);
765 static int dispatch_http_event(sd_event_source *event,
769 MHDDaemonWrapper *d = userdata;
774 r = MHD_run(d->daemon);
776 log_error("MHD_run failed!");
777 // XXX: unregister daemon
781 return 1; /* work to do */
784 /**********************************************************************
785 **********************************************************************
786 **********************************************************************/
788 static int setup_signals(RemoteServer *s) {
794 assert_se(sigemptyset(&mask) == 0);
795 sigset_add_many(&mask, SIGINT, SIGTERM, -1);
796 assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
798 r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, NULL, s);
802 r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, NULL, s);
809 static int negative_fd(const char *spec) {
810 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
814 r = safe_atoi(spec, &fd);
824 static int remoteserver_init(RemoteServer *s,
833 if ((arg_listen_raw || arg_listen_http) && trust) {
834 log_error("Option --trust makes all non-HTTPS connections untrusted.");
838 r = sd_event_default(&s->events);
840 log_error_errno(r, "Failed to allocate event loop: %m");
846 assert(server == NULL);
849 r = init_writer_hashmap(s);
853 n = sd_listen_fds(true);
855 return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
857 log_info("Received %d descriptors", n);
859 if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
860 log_error("Received fewer sockets than expected");
864 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
865 if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
866 log_info("Received a listening socket (fd:%d)", fd);
868 if (fd == http_socket)
869 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
870 else if (fd == https_socket)
871 r = setup_microhttpd_server(s, fd, key, cert, trust);
873 r = add_raw_socket(s, fd);
874 } else if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
877 r = getnameinfo_pretty(fd, &hostname);
879 log_error_errno(r, "Failed to retrieve remote name: %m");
883 log_info("Received a connection socket (fd:%d) from %s", fd, hostname);
885 r = add_source(s, fd, hostname, true);
887 log_error("Unknown socket passed on fd:%d", fd);
893 log_error_errno(r, "Failed to register socket (fd:%d): %m",
900 const char *url, *hostname;
902 url = strappenda(arg_url, "/entries");
905 log_info("Spawning getter %s...", url);
906 fd = spawn_getter(arg_getter, url);
908 log_info("Spawning curl %s...", url);
909 fd = spawn_curl(url);
915 startswith(arg_url, "https://") ?:
916 startswith(arg_url, "http://") ?:
919 r = add_source(s, fd, (char*) hostname, false);
924 if (arg_listen_raw) {
925 log_info("Listening on a socket...");
926 r = setup_raw_socket(s, arg_listen_raw);
931 if (arg_listen_http) {
932 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
937 if (arg_listen_https) {
938 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
943 STRV_FOREACH(file, arg_files) {
944 const char *output_name;
946 if (streq(*file, "-")) {
947 log_info("Using standard input as source.");
950 output_name = "stdin";
952 log_info("Reading file %s...", *file);
954 fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
956 log_error("Failed to open %s: %m", *file);
962 r = add_source(s, fd, (char*) output_name, false);
967 if (s->active == 0) {
968 log_error("Zarro sources specified");
972 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) {
973 /* In this case we know what the writer will be
974 called, so we can create it and verify that we can
975 create output as expected. */
976 r = get_writer(s, NULL, &s->_single_writer);
984 static void server_destroy(RemoteServer *s) {
988 while ((d = hashmap_steal_first(s->daemons))) {
989 MHD_stop_daemon(d->daemon);
990 sd_event_source_unref(d->event);
994 hashmap_free(s->daemons);
996 assert(s->sources_size == 0 || s->sources);
997 for (i = 0; i < s->sources_size; i++)
1001 writer_unref(s->_single_writer);
1002 hashmap_free(s->writers);
1004 sd_event_source_unref(s->sigterm_event);
1005 sd_event_source_unref(s->sigint_event);
1006 sd_event_source_unref(s->listen_event);
1007 sd_event_unref(s->events);
1009 /* fds that we're listening on remain open... */
1012 /**********************************************************************
1013 **********************************************************************
1014 **********************************************************************/
1016 static int dispatch_raw_source_event(sd_event_source *event,
1021 RemoteServer *s = userdata;
1022 RemoteSource *source;
1025 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
1026 source = s->sources[fd];
1027 assert(source->fd == fd);
1029 r = process_source(source, arg_compress, arg_seal);
1030 if (source->state == STATE_EOF) {
1033 log_info("EOF reached with source fd:%d (%s)",
1034 source->fd, source->name);
1036 remaining = source_non_empty(source);
1038 log_warning("Premature EOF. %zu bytes lost.", remaining);
1039 remove_source(s, source->fd);
1040 log_info("%zd active sources remaining", s->active);
1042 } else if (r == -E2BIG) {
1043 log_error("Entry too big, skipped");
1045 } else if (r == -EAGAIN) {
1048 log_info_errno(r, "Closing connection: %m");
1049 remove_source(server, fd);
1055 static int dispatch_blocking_source_event(sd_event_source *event,
1057 RemoteSource *source = userdata;
1059 return dispatch_raw_source_event(event, source->fd, EPOLLIN, server);
1062 static int accept_connection(const char* type, int fd,
1063 SocketAddress *addr, char **hostname) {
1066 log_debug("Accepting new %s connection on fd:%d", type, fd);
1067 fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
1069 log_error("accept() on fd:%d failed: %m", fd);
1073 switch(socket_address_family(addr)) {
1076 _cleanup_free_ char *a = NULL;
1079 r = socket_address_print(addr, &a);
1081 log_error_errno(r, "socket_address_print(): %m");
1086 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
1092 log_info("Accepted %s %s connection from %s",
1094 socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
1102 log_error("Rejected %s connection with unsupported family %d",
1103 type, socket_address_family(addr));
1110 static int dispatch_raw_connection_event(sd_event_source *event,
1114 RemoteServer *s = userdata;
1116 SocketAddress addr = {
1117 .size = sizeof(union sockaddr_union),
1118 .type = SOCK_STREAM,
1122 fd2 = accept_connection("raw", fd, &addr, &hostname);
1126 return add_source(s, fd2, hostname, true);
1129 /**********************************************************************
1130 **********************************************************************
1131 **********************************************************************/
1133 static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
1134 [JOURNAL_WRITE_SPLIT_NONE] = "none",
1135 [JOURNAL_WRITE_SPLIT_HOST] = "host",
1138 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
1139 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
1140 journal_write_split_mode,
1141 JournalWriteSplitMode,
1142 "Failed to parse split mode setting");
1144 static int parse_config(void) {
1145 const ConfigTableItem items[] = {
1146 { "Remote", "SplitMode", config_parse_write_split_mode, 0, &arg_split_mode },
1147 { "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key },
1148 { "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert },
1149 { "Remote", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
1152 return config_parse(NULL, PKGSYSCONFDIR "/journal-remote.conf", NULL,
1154 config_item_table_lookup, items,
1155 false, false, true, NULL);
1158 static void help(void) {
1159 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1160 "Write external journal events to journal file(s).\n\n"
1161 " -h --help Show this help\n"
1162 " --version Show package version\n"
1163 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1164 " --getter=COMMAND Read events from the output of COMMAND\n"
1165 " --listen-raw=ADDR Listen for connections at ADDR\n"
1166 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1167 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1168 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1169 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1170 " --seal[=BOOL] Use event sealing (default: no)\n"
1171 " --key=FILENAME SSL key in PEM format (default:\n"
1172 " \"" PRIV_KEY_FILE "\")\n"
1173 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1174 " \"" CERT_FILE "\")\n"
1175 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1176 " \"" TRUST_FILE "\")\n"
1177 " --gnutls-log=CATEGORY...\n"
1178 " Specify a list of gnutls logging categories\n"
1179 " --split-mode=none|host How many output files to create\n"
1181 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1182 , program_invocation_short_name);
1185 static int parse_argv(int argc, char *argv[]) {
1187 ARG_VERSION = 0x100,
1202 static const struct option options[] = {
1203 { "help", no_argument, NULL, 'h' },
1204 { "version", no_argument, NULL, ARG_VERSION },
1205 { "url", required_argument, NULL, ARG_URL },
1206 { "getter", required_argument, NULL, ARG_GETTER },
1207 { "listen-raw", required_argument, NULL, ARG_LISTEN_RAW },
1208 { "listen-http", required_argument, NULL, ARG_LISTEN_HTTP },
1209 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1210 { "output", required_argument, NULL, 'o' },
1211 { "split-mode", required_argument, NULL, ARG_SPLIT_MODE },
1212 { "compress", optional_argument, NULL, ARG_COMPRESS },
1213 { "seal", optional_argument, NULL, ARG_SEAL },
1214 { "key", required_argument, NULL, ARG_KEY },
1215 { "cert", required_argument, NULL, ARG_CERT },
1216 { "trust", required_argument, NULL, ARG_TRUST },
1217 { "gnutls-log", required_argument, NULL, ARG_GNUTLS_LOG },
1222 bool type_a, type_b;
1227 while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1231 return 0 /* done */;
1234 puts(PACKAGE_STRING);
1235 puts(SYSTEMD_FEATURES);
1236 return 0 /* done */;
1240 log_error("cannot currently set more than one --url");
1249 log_error("cannot currently use --getter more than once");
1253 arg_getter = optarg;
1256 case ARG_LISTEN_RAW:
1257 if (arg_listen_raw) {
1258 log_error("cannot currently use --listen-raw more than once");
1262 arg_listen_raw = optarg;
1265 case ARG_LISTEN_HTTP:
1266 if (arg_listen_http || http_socket >= 0) {
1267 log_error("cannot currently use --listen-http more than once");
1271 r = negative_fd(optarg);
1275 arg_listen_http = optarg;
1278 case ARG_LISTEN_HTTPS:
1279 if (arg_listen_https || https_socket >= 0) {
1280 log_error("cannot currently use --listen-https more than once");
1284 r = negative_fd(optarg);
1288 arg_listen_https = optarg;
1294 log_error("Key file specified twice");
1298 arg_key = strdup(optarg);
1306 log_error("Certificate file specified twice");
1310 arg_cert = strdup(optarg);
1317 if (arg_trust || arg_trust_all) {
1318 log_error("Confusing trusted CA configuration");
1322 if (streq(optarg, "all"))
1323 arg_trust_all = true;
1326 arg_trust = strdup(optarg);
1330 log_error("Option --trust is not available.");
1339 log_error("cannot use --output/-o more than once");
1343 arg_output = optarg;
1346 case ARG_SPLIT_MODE:
1347 arg_split_mode = journal_write_split_mode_from_string(optarg);
1348 if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) {
1349 log_error("Invalid split mode: %s", optarg);
1356 r = parse_boolean(optarg);
1358 log_error("Failed to parse --compress= parameter.");
1364 arg_compress = true;
1370 r = parse_boolean(optarg);
1372 log_error("Failed to parse --seal= parameter.");
1382 case ARG_GNUTLS_LOG: {
1384 const char *word, *state;
1387 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
1390 cat = strndup(word, size);
1394 if (strv_consume(&arg_gnutls_log, cat) < 0)
1399 log_error("Option --gnutls-log is not available.");
1408 assert_not_reached("Unknown option code.");
1412 arg_files = argv + optind;
1414 type_a = arg_getter || !strv_isempty(arg_files);
1417 || arg_listen_http || arg_listen_https
1418 || sd_listen_fds(false) > 0;
1419 if (type_a && type_b) {
1420 log_error("Cannot use file input or --getter with "
1421 "--arg-listen-... or socket activation.");
1426 log_error("Option --output must be specified with file input or --getter.");
1430 arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
1433 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE
1434 && arg_output && is_dir(arg_output, true) > 0) {
1435 log_error("For SplitMode=none, output must be a file.");
1439 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
1440 && arg_output && is_dir(arg_output, true) <= 0) {
1441 log_error("For SplitMode=host, output must be a directory.");
1445 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1446 journal_write_split_mode_to_string(arg_split_mode),
1451 return 1 /* work to do */;
1454 static int load_certificates(char **key, char **cert, char **trust) {
1457 r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
1459 return log_error_errno(r, "Failed to read key from file '%s': %m",
1460 arg_key ?: PRIV_KEY_FILE);
1462 r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1464 return log_error_errno(r, "Failed to read certificate from file '%s': %m",
1465 arg_cert ?: CERT_FILE);
1468 log_info("Certificate checking disabled.");
1470 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1472 return log_error_errno(r, "Failed to read CA certificate file '%s': %m",
1473 arg_trust ?: TRUST_FILE);
1479 static int setup_gnutls_logger(char **categories) {
1480 if (!arg_listen_http && !arg_listen_https)
1488 gnutls_global_set_log_function(log_func_gnutls);
1491 STRV_FOREACH(cat, categories) {
1492 r = log_enable_gnutls_category(*cat);
1497 log_reset_gnutls_level();
1504 int main(int argc, char **argv) {
1505 RemoteServer s = {};
1507 _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1509 log_show_color(true);
1510 log_parse_environment();
1514 return EXIT_FAILURE;
1516 r = parse_argv(argc, argv);
1518 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1520 r = setup_gnutls_logger(arg_gnutls_log);
1522 return EXIT_FAILURE;
1524 if (arg_listen_https || https_socket >= 0)
1525 if (load_certificates(&key, &cert, &trust) < 0)
1526 return EXIT_FAILURE;
1528 if (remoteserver_init(&s, key, cert, trust) < 0)
1529 return EXIT_FAILURE;
1531 r = sd_event_set_watchdog(s.events, true);
1533 log_error_errno(r, "Failed to enable watchdog: %m");
1535 log_debug("Watchdog is %s.", r > 0 ? "enabled" : "disabled");
1537 log_debug("%s running as pid "PID_FMT,
1538 program_invocation_short_name, getpid());
1541 "STATUS=Processing requests...");
1544 r = sd_event_get_state(s.events);
1547 if (r == SD_EVENT_FINISHED)
1550 r = sd_event_run(s.events, -1);
1552 log_error_errno(r, "Failed to run event loop: %m");
1559 "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
1560 log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
1568 return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;