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/>.
28 #include <sys/prctl.h>
29 #include <sys/socket.h>
31 #include <sys/types.h>
35 #include "sd-daemon.h"
37 #include "journal-file.h"
38 #include "journald-native.h"
39 #include "socket-util.h"
45 #include "conf-parser.h"
46 #include "microhttpd-util.h"
49 #include <gnutls/gnutls.h>
52 #include "journal-remote-parse.h"
53 #include "journal-remote-write.h"
55 #define REMOTE_JOURNAL_PATH "/var/log/journal/" SD_ID128_FORMAT_STR "/remote-%s.journal"
57 #define KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
58 #define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
59 #define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
61 static char* arg_output = NULL;
62 static char* arg_url = NULL;
63 static char* arg_getter = NULL;
64 static char* arg_listen_raw = NULL;
65 static char* arg_listen_http = NULL;
66 static char* arg_listen_https = NULL;
67 static char** arg_files = NULL;
68 static int arg_compress = true;
69 static int arg_seal = false;
70 static int http_socket = -1, https_socket = -1;
71 static char** arg_gnutls_log = 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(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(char *getter, char *url) {
149 _cleanup_strv_free_ char **words = NULL;
152 words = strv_split_quoted(getter);
156 r = spawn_child(words[0], words);
158 log_error("Failed to spawn getter %s: %m", getter);
163 static int open_output(Writer *s, const char* url) {
164 _cleanup_free_ char *name, *output = NULL;
173 for(c = name; *c; c++) {
174 if (*c == '/' || *c == ':' || *c == ' ')
176 else if (*c == '?') {
184 r = sd_id128_get_machine(&machine);
186 log_error("failed to determine machine ID128: %s", strerror(-r));
190 r = asprintf(&output, REMOTE_JOURNAL_PATH,
191 SD_ID128_FORMAT_VAL(machine), name);
195 r = is_dir(arg_output, true);
197 r = asprintf(&output,
198 "%s/remote-%s.journal", arg_output, name);
202 output = strdup(arg_output);
208 r = journal_file_open_reliably(output,
209 O_RDWR|O_CREAT, 0640,
210 arg_compress, arg_seal,
215 log_error("Failed to open output journal %s: %s",
216 arg_output, strerror(-r));
218 log_info("Opened output file %s", s->journal->path);
222 /**********************************************************************
223 **********************************************************************
224 **********************************************************************/
226 typedef struct MHDDaemonWrapper {
228 struct MHD_Daemon *daemon;
230 sd_event_source *event;
233 typedef struct RemoteServer {
234 RemoteSource **sources;
239 sd_event_source *sigterm_event, *sigint_event, *listen_event;
247 /* This should go away as soon as µhttpd allows state to be passed around. */
248 static RemoteServer *server;
250 static int dispatch_raw_source_event(sd_event_source *event,
254 static int dispatch_raw_connection_event(sd_event_source *event,
258 static int dispatch_http_event(sd_event_source *event,
263 static int get_source_for_fd(RemoteServer *s, int fd, RemoteSource **source) {
267 if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
270 if (s->sources[fd] == NULL) {
271 s->sources[fd] = new0(RemoteSource, 1);
274 s->sources[fd]->fd = -1;
278 *source = s->sources[fd];
282 static int remove_source(RemoteServer *s, int fd) {
283 RemoteSource *source;
286 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
288 source = s->sources[fd];
291 s->sources[fd] = NULL;
300 static int add_source(RemoteServer *s, int fd, const char* name) {
301 RemoteSource *source = NULL;
302 _cleanup_free_ char *realname = NULL;
309 realname = strdup(name);
313 r = asprintf(&realname, "fd:%d", fd);
318 log_debug("Creating source for fd:%d (%s)", fd, realname);
320 r = get_source_for_fd(s, fd, &source);
322 log_error("Failed to create source for fd:%d (%s)", fd, realname);
326 assert(source->fd < 0);
329 r = sd_event_add_io(s->events, &source->event,
330 fd, EPOLLIN, dispatch_raw_source_event, s);
332 log_error("Failed to register event source for fd:%d: %s",
337 return 1; /* work to do */
340 remove_source(s, fd);
344 static int add_raw_socket(RemoteServer *s, int fd) {
347 r = sd_event_add_io(s->events, &s->listen_event, fd, EPOLLIN,
348 dispatch_raw_connection_event, s);
358 static int setup_raw_socket(RemoteServer *s, const char *address) {
361 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
365 return add_raw_socket(s, fd);
368 /**********************************************************************
369 **********************************************************************
370 **********************************************************************/
372 static RemoteSource *request_meta(void **connection_cls) {
373 RemoteSource *source;
375 assert(connection_cls);
377 return *connection_cls;
379 source = new0(RemoteSource, 1);
384 log_debug("Added RemoteSource as connection metadata %p", source);
386 *connection_cls = source;
390 static void request_meta_free(void *cls,
391 struct MHD_Connection *connection,
392 void **connection_cls,
393 enum MHD_RequestTerminationCode toe) {
396 assert(connection_cls);
399 log_debug("Cleaning up connection metadata %p", s);
401 *connection_cls = NULL;
404 static int process_http_upload(
405 struct MHD_Connection *connection,
406 const char *upload_data,
407 size_t *upload_data_size,
408 RemoteSource *source) {
410 bool finished = false;
415 log_debug("request_handler_upload: connection %p, %zu bytes",
416 connection, *upload_data_size);
418 if (*upload_data_size) {
419 log_info("Received %zu bytes", *upload_data_size);
421 r = push_data(source, upload_data, *upload_data_size);
423 return mhd_respond_oom(connection);
425 *upload_data_size = 0;
430 r = process_source(source, &server->writer, arg_compress, arg_seal);
431 if (r == -EAGAIN || r == -EWOULDBLOCK)
434 log_warning("Failed to process data for connection %p", connection);
436 return mhd_respondf(connection,
437 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
438 "Entry is too large, maximum is %u bytes.\n",
441 return mhd_respondf(connection,
442 MHD_HTTP_UNPROCESSABLE_ENTITY,
443 "Processing failed: %s.", strerror(-r));
450 /* The upload is finished */
452 if (source_non_empty(source)) {
453 log_warning("EOF reached with incomplete data");
454 return mhd_respond(connection, MHD_HTTP_EXPECTATION_FAILED,
455 "Trailing data not processed.");
458 return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
461 static int request_handler(
463 struct MHD_Connection *connection,
467 const char *upload_data,
468 size_t *upload_data_size,
469 void **connection_cls) {
475 assert(connection_cls);
479 log_debug("Handling a connection %s %s %s", method, url, version);
482 return process_http_upload(connection,
483 upload_data, upload_data_size,
486 if (!streq(method, "POST"))
487 return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
488 "Unsupported method.\n");
490 if (!streq(url, "/upload"))
491 return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
494 header = MHD_lookup_connection_value(connection,
495 MHD_HEADER_KIND, "Content-Type");
496 if (!header || !streq(header, "application/vnd.fdo.journal"))
497 return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
498 "Content-Type: application/vnd.fdo.journal"
501 if (server->check_trust) {
502 r = check_permissions(connection, &code);
507 if (!request_meta(connection_cls))
508 return respond_oom(connection);
512 static int setup_microhttpd_server(RemoteServer *s,
517 struct MHD_OptionItem opts[] = {
518 { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
519 { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
520 { MHD_OPTION_LISTEN_SOCKET, fd},
528 MHD_USE_PEDANTIC_CHECKS |
529 MHD_USE_EPOLL_LINUX_ONLY |
532 const union MHD_DaemonInfo *info;
538 r = fd_nonblock(fd, true);
540 log_error("Failed to make fd:%d nonblocking: %s", fd, strerror(-r));
547 opts[opts_pos++] = (struct MHD_OptionItem)
548 {MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
549 opts[opts_pos++] = (struct MHD_OptionItem)
550 {MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
552 flags |= MHD_USE_SSL;
555 opts[opts_pos++] = (struct MHD_OptionItem)
556 {MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
559 d = new(MHDDaemonWrapper, 1);
563 d->fd = (uint64_t) fd;
565 d->daemon = MHD_start_daemon(flags, 0,
567 request_handler, NULL,
568 MHD_OPTION_ARRAY, opts,
571 log_error("Failed to start µhttp daemon");
576 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
577 key ? "HTTPS" : "HTTP", fd, d);
580 info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
582 log_error("µhttp returned NULL daemon info");
587 epoll_fd = info->listen_fd;
589 log_error("µhttp epoll fd is invalid");
594 r = sd_event_add_io(s->events, &d->event,
595 epoll_fd, EPOLLIN, dispatch_http_event, d);
597 log_error("Failed to add event callback: %s", strerror(-r));
601 r = hashmap_ensure_allocated(&s->daemons, uint64_hash_func, uint64_compare_func);
607 r = hashmap_put(s->daemons, &d->fd, d);
609 log_error("Failed to add daemon to hashmap: %s", strerror(-r));
617 MHD_stop_daemon(d->daemon);
623 static int setup_microhttpd_socket(RemoteServer *s,
630 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
634 return setup_microhttpd_server(s, fd, key, cert, trust);
637 static int dispatch_http_event(sd_event_source *event,
641 MHDDaemonWrapper *d = userdata;
646 r = MHD_run(d->daemon);
648 log_error("MHD_run failed!");
649 // XXX: unregister daemon
653 return 1; /* work to do */
656 /**********************************************************************
657 **********************************************************************
658 **********************************************************************/
660 static int dispatch_sigterm(sd_event_source *event,
661 const struct signalfd_siginfo *si,
663 RemoteServer *s = userdata;
667 log_received_signal(LOG_INFO, si);
669 sd_event_exit(s->events, 0);
673 static int setup_signals(RemoteServer *s) {
679 assert_se(sigemptyset(&mask) == 0);
680 sigset_add_many(&mask, SIGINT, SIGTERM, -1);
681 assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
683 r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, dispatch_sigterm, s);
687 r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, dispatch_sigterm, s);
694 static int fd_fd(const char *spec) {
697 r = safe_atoi(spec, &fd);
708 static int remoteserver_init(RemoteServer *s,
713 const char *output_name = NULL;
719 if ((arg_listen_raw || arg_listen_http) && trust) {
720 log_error("Option --trust makes all non-HTTPS connections untrusted.");
724 sd_event_default(&s->events);
728 assert(server == NULL);
731 n = sd_listen_fds(true);
733 log_error("Failed to read listening file descriptors from environment: %s",
737 log_info("Received %d descriptors", n);
739 if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
740 log_error("Received fewer sockets than expected");
744 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
745 if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
746 log_info("Received a listening socket (fd:%d)", fd);
748 if (fd == http_socket)
749 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
750 else if (fd == https_socket)
751 r = setup_microhttpd_server(s, fd, key, cert, trust);
753 r = add_raw_socket(s, fd);
754 } else if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
755 log_info("Received a connection socket (fd:%d)", fd);
757 r = add_source(s, fd, NULL);
759 log_error("Unknown socket passed on fd:%d", fd);
765 log_error("Failed to register socket (fd:%d): %s",
770 output_name = "socket";
774 _cleanup_free_ char *url = NULL;
775 _cleanup_strv_free_ char **urlv = strv_new(arg_url, "/entries", NULL);
778 url = strv_join(urlv, "");
783 log_info("Spawning getter %s...", url);
784 fd = spawn_getter(arg_getter, url);
786 log_info("Spawning curl %s...", url);
787 fd = spawn_curl(url);
792 r = add_source(s, fd, arg_url);
796 output_name = arg_url;
799 if (arg_listen_raw) {
800 log_info("Listening on a socket...");
801 r = setup_raw_socket(s, arg_listen_raw);
805 output_name = arg_listen_raw;
808 if (arg_listen_http) {
809 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
813 output_name = arg_listen_http;
816 if (arg_listen_https) {
817 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
821 output_name = arg_listen_https;
824 STRV_FOREACH(file, arg_files) {
825 if (streq(*file, "-")) {
826 log_info("Reading standard input...");
829 output_name = "stdin";
831 log_info("Reading file %s...", *file);
833 fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
835 log_error("Failed to open %s: %m", *file);
841 r = add_source(s, fd, output_name);
846 if (s->active == 0) {
847 log_error("Zarro sources specified");
851 if (!!n + !!arg_url + !!arg_listen_raw + !!arg_files)
852 output_name = "multiple";
854 r = writer_init(&s->writer);
858 r = open_output(&s->writer, output_name);
862 static int server_destroy(RemoteServer *s) {
867 r = writer_close(&s->writer);
869 while ((d = hashmap_steal_first(s->daemons))) {
870 MHD_stop_daemon(d->daemon);
871 sd_event_source_unref(d->event);
875 hashmap_free(s->daemons);
877 assert(s->sources_size == 0 || s->sources);
878 for (i = 0; i < s->sources_size; i++)
883 sd_event_source_unref(s->sigterm_event);
884 sd_event_source_unref(s->sigint_event);
885 sd_event_source_unref(s->listen_event);
886 sd_event_unref(s->events);
888 /* fds that we're listening on remain open... */
893 /**********************************************************************
894 **********************************************************************
895 **********************************************************************/
897 static int dispatch_raw_source_event(sd_event_source *event,
902 RemoteServer *s = userdata;
903 RemoteSource *source;
906 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
907 source = s->sources[fd];
908 assert(source->fd == fd);
910 r = process_source(source, &s->writer, arg_compress, arg_seal);
911 if (source->state == STATE_EOF) {
912 log_info("EOF reached with source fd:%d (%s)",
913 source->fd, source->name);
914 if (source_non_empty(source))
915 log_warning("EOF reached with incomplete data");
916 remove_source(s, source->fd);
917 log_info("%zd active source remaining", s->active);
918 } else if (r == -E2BIG) {
919 log_error("Entry too big, skipped");
926 static int accept_connection(const char* type, int fd, SocketAddress *addr) {
929 log_debug("Accepting new %s connection on fd:%d", type, fd);
930 fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
932 log_error("accept() on fd:%d failed: %m", fd);
936 switch(socket_address_family(addr)) {
939 char* _cleanup_free_ a = NULL;
941 r = socket_address_print(addr, &a);
943 log_error("socket_address_print(): %s", strerror(-r));
948 log_info("Accepted %s %s connection from %s",
950 socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
956 log_error("Rejected %s connection with unsupported family %d",
957 type, socket_address_family(addr));
964 static int dispatch_raw_connection_event(sd_event_source *event,
968 RemoteServer *s = userdata;
970 SocketAddress addr = {
971 .size = sizeof(union sockaddr_union),
975 fd2 = accept_connection("raw", fd, &addr);
979 return add_source(s, fd2, NULL);
982 /**********************************************************************
983 **********************************************************************
984 **********************************************************************/
986 static int parse_config(void) {
987 const ConfigTableItem items[] = {
988 { "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key },
989 { "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert },
990 { "Remote", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
994 r = config_parse(NULL, PKGSYSCONFDIR "/journal-remote.conf", NULL,
996 config_item_table_lookup, items,
999 log_error("Failed to parse configuration file: %s", strerror(-r));
1004 static void help(void) {
1005 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1006 "Write external journal events to a journal file.\n\n"
1008 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1009 " --getter=COMMAND Read events from the output of COMMAND\n"
1010 " --listen-raw=ADDR Listen for connections at ADDR\n"
1011 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1012 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1013 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1014 " --[no-]compress Use XZ-compression in the output journal (default: yes)\n"
1015 " --[no-]seal Use Event sealing in the output journal (default: no)\n"
1016 " --key=FILENAME Specify key in PEM format (default:\n"
1017 " \"" KEY_FILE "\")\n"
1018 " --cert=FILENAME Specify certificate in PEM format (default:\n"
1019 " \"" CERT_FILE "\")\n"
1020 " --trust=FILENAME|all Specify CA certificate or disable checking (default:\n"
1021 " \"" TRUST_FILE "\")\n"
1022 " --gnutls-log=CATEGORY...\n"
1023 " Specify a list of gnutls logging categories\n"
1024 " -h --help Show this help and exit\n"
1025 " --version Print version string and exit\n"
1027 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1028 , program_invocation_short_name);
1031 static int parse_argv(int argc, char *argv[]) {
1033 ARG_VERSION = 0x100,
1049 static const struct option options[] = {
1050 { "help", no_argument, NULL, 'h' },
1051 { "version", no_argument, NULL, ARG_VERSION },
1052 { "url", required_argument, NULL, ARG_URL },
1053 { "getter", required_argument, NULL, ARG_GETTER },
1054 { "listen-raw", required_argument, NULL, ARG_LISTEN_RAW },
1055 { "listen-http", required_argument, NULL, ARG_LISTEN_HTTP },
1056 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1057 { "output", required_argument, NULL, 'o' },
1058 { "compress", no_argument, NULL, ARG_COMPRESS },
1059 { "no-compress", no_argument, NULL, ARG_NO_COMPRESS },
1060 { "seal", no_argument, NULL, ARG_SEAL },
1061 { "no-seal", no_argument, NULL, ARG_NO_SEAL },
1062 { "key", required_argument, NULL, ARG_KEY },
1063 { "cert", required_argument, NULL, ARG_CERT },
1064 { "trust", required_argument, NULL, ARG_TRUST },
1065 { "gnutls-log", required_argument, NULL, ARG_GNUTLS_LOG },
1074 while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1078 return 0 /* done */;
1081 puts(PACKAGE_STRING);
1082 puts(SYSTEMD_FEATURES);
1083 return 0 /* done */;
1087 log_error("cannot currently set more than one --url");
1096 log_error("cannot currently use --getter more than once");
1100 arg_getter = optarg;
1103 case ARG_LISTEN_RAW:
1104 if (arg_listen_raw) {
1105 log_error("cannot currently use --listen-raw more than once");
1109 arg_listen_raw = optarg;
1112 case ARG_LISTEN_HTTP:
1113 if (arg_listen_http || http_socket >= 0) {
1114 log_error("cannot currently use --listen-http more than once");
1121 else if (r == -ENOENT)
1122 arg_listen_http = optarg;
1124 log_error("Invalid port/fd specification %s: %s",
1125 optarg, strerror(-r));
1131 case ARG_LISTEN_HTTPS:
1132 if (arg_listen_https || https_socket >= 0) {
1133 log_error("cannot currently use --listen-https more than once");
1140 else if (r == -ENOENT)
1141 arg_listen_https = optarg;
1143 log_error("Invalid port/fd specification %s: %s",
1144 optarg, strerror(-r));
1152 log_error("Key file specified twice");
1156 arg_key = strdup(optarg);
1164 log_error("Certificate file specified twice");
1168 arg_cert = strdup(optarg);
1175 if (arg_trust || arg_trust_all) {
1176 log_error("Confusing trusted CA configuration");
1180 if (streq(optarg, "all"))
1181 arg_trust_all = true;
1184 arg_trust = strdup(optarg);
1188 log_error("Option --trust is not available.");
1197 log_error("cannot use --output/-o more than once");
1201 arg_output = optarg;
1205 arg_compress = true;
1207 case ARG_NO_COMPRESS:
1208 arg_compress = false;
1217 case ARG_GNUTLS_LOG: {
1222 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
1225 cat = strndup(word, size);
1229 if (strv_consume(&arg_gnutls_log, cat) < 0)
1234 log_error("Option --gnutls-log is not available.");
1243 log_error("Unknown option code %c", c);
1248 arg_files = argv + optind;
1250 return 1 /* work to do */;
1253 static int load_certificates(char **key, char **cert, char **trust) {
1256 r = read_full_file(arg_key ?: KEY_FILE, key, NULL);
1258 log_error("Failed to read key from file '%s': %s",
1259 arg_key ?: KEY_FILE, strerror(-r));
1263 r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1265 log_error("Failed to read certificate from file '%s': %s",
1266 arg_cert ?: CERT_FILE, strerror(-r));
1271 log_info("Certificate checking disabled.");
1273 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1275 log_error("Failed to read CA certificate file '%s': %s",
1276 arg_trust ?: TRUST_FILE, strerror(-r));
1284 static int setup_gnutls_logger(char **categories) {
1285 if (!arg_listen_http && !arg_listen_https)
1293 gnutls_global_set_log_function(log_func_gnutls);
1296 STRV_FOREACH(cat, categories) {
1297 r = log_enable_gnutls_category(*cat);
1302 log_reset_gnutls_level();
1309 int main(int argc, char **argv) {
1310 RemoteServer s = {};
1312 _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1314 log_show_color(true);
1315 log_parse_environment();
1319 return EXIT_FAILURE;
1321 r = parse_argv(argc, argv);
1323 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1325 r = setup_gnutls_logger(arg_gnutls_log);
1327 return EXIT_FAILURE;
1329 if (load_certificates(&key, &cert, &trust) < 0)
1330 return EXIT_FAILURE;
1332 if (remoteserver_init(&s, key, cert, trust) < 0)
1333 return EXIT_FAILURE;
1335 sd_event_set_watchdog(s.events, true);
1337 log_debug("%s running as pid "PID_FMT,
1338 program_invocation_short_name, getpid());
1341 "STATUS=Processing requests...");
1344 r = sd_event_get_state(s.events);
1347 if (r == SD_EVENT_FINISHED)
1350 r = sd_event_run(s.events, -1);
1352 log_error("Failed to run event loop: %s", strerror(-r));
1357 log_info("Finishing after writing %" PRIu64 " entries", s.writer.seqnum);
1358 r2 = server_destroy(&s);
1360 sd_notify(false, "STATUS=Shutting down...");
1366 return r >= 0 && r2 >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;