1 /* SPDX-License-Identifier: LGPL-2.1+ */
8 #include "conf-parser.h"
12 #include "journal-remote-write.h"
13 #include "journal-remote.h"
14 #include "pretty-print.h"
15 #include "process-util.h"
16 #include "rlimit-util.h"
17 #include "signal-util.h"
18 #include "socket-util.h"
19 #include "stat-util.h"
20 #include "string-table.h"
23 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
24 #define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
25 #define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
27 static char* arg_url
= NULL
;
28 static char* arg_getter
= NULL
;
29 static char* arg_listen_raw
= NULL
;
30 static char* arg_listen_http
= NULL
;
31 static char* arg_listen_https
= NULL
;
32 static char** arg_files
= NULL
;
33 static int arg_compress
= true;
34 static int arg_seal
= false;
35 static int http_socket
= -1, https_socket
= -1;
36 static char** arg_gnutls_log
= NULL
;
38 static JournalWriteSplitMode arg_split_mode
= _JOURNAL_WRITE_SPLIT_INVALID
;
39 static char* arg_output
= NULL
;
41 static char *arg_key
= NULL
;
42 static char *arg_cert
= NULL
;
43 static char *arg_trust
= NULL
;
44 static bool arg_trust_all
= false;
46 static const char* const journal_write_split_mode_table
[_JOURNAL_WRITE_SPLIT_MAX
] = {
47 [JOURNAL_WRITE_SPLIT_NONE
] = "none",
48 [JOURNAL_WRITE_SPLIT_HOST
] = "host",
51 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode
, JournalWriteSplitMode
);
52 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode
,
53 journal_write_split_mode
,
54 JournalWriteSplitMode
,
55 "Failed to parse split mode setting");
57 /**********************************************************************
58 **********************************************************************
59 **********************************************************************/
61 static int spawn_child(const char* child
, char** argv
) {
66 return log_error_errno(errno
, "Failed to create pager pipe: %m");
68 r
= safe_fork("(remote)", FORK_RESET_SIGNALS
|FORK_DEATHSIG
|FORK_LOG
, &child_pid
);
78 r
= rearrange_stdio(STDIN_FILENO
, fd
[1], STDERR_FILENO
);
80 log_error_errno(r
, "Failed to dup pipe to stdout: %m");
85 log_error_errno(errno
, "Failed to exec child %s: %m", child
);
91 r
= fd_nonblock(fd
[0], true);
93 log_warning_errno(errno
, "Failed to set child pipe to non-blocking: %m");
98 static int spawn_curl(const char* url
) {
99 char **argv
= STRV_MAKE("curl",
100 "-HAccept: application/vnd.fdo.journal",
106 r
= spawn_child("curl", argv
);
108 log_error_errno(r
, "Failed to spawn curl: %m");
112 static int spawn_getter(const char *getter
) {
114 _cleanup_strv_free_
char **words
= NULL
;
117 r
= strv_split_extract(&words
, getter
, WHITESPACE
, EXTRACT_QUOTES
);
119 return log_error_errno(r
, "Failed to split getter option: %m");
121 r
= spawn_child(words
[0], words
);
123 log_error_errno(r
, "Failed to spawn getter %s: %m", getter
);
128 /**********************************************************************
129 **********************************************************************
130 **********************************************************************/
132 static int null_timer_event_handler(sd_event_source
*s
,
135 static int dispatch_http_event(sd_event_source
*event
,
140 static int request_meta(void **connection_cls
, int fd
, char *hostname
) {
141 RemoteSource
*source
;
145 assert(connection_cls
);
149 r
= journal_remote_get_writer(journal_remote_server_global
, hostname
, &writer
);
151 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
154 source
= source_new(fd
, true, hostname
, writer
);
156 writer_unref(writer
);
160 log_debug("Added RemoteSource as connection metadata %p", source
);
162 *connection_cls
= source
;
166 static void request_meta_free(void *cls
,
167 struct MHD_Connection
*connection
,
168 void **connection_cls
,
169 enum MHD_RequestTerminationCode toe
) {
172 assert(connection_cls
);
176 log_debug("Cleaning up connection metadata %p", s
);
178 *connection_cls
= NULL
;
182 static int process_http_upload(
183 struct MHD_Connection
*connection
,
184 const char *upload_data
,
185 size_t *upload_data_size
,
186 RemoteSource
*source
) {
188 bool finished
= false;
194 log_trace("%s: connection %p, %zu bytes",
195 __func__
, connection
, *upload_data_size
);
197 if (*upload_data_size
) {
198 log_trace("Received %zu bytes", *upload_data_size
);
200 r
= journal_importer_push_data(&source
->importer
,
201 upload_data
, *upload_data_size
);
203 return mhd_respond_oom(connection
);
205 *upload_data_size
= 0;
210 r
= process_source(source
,
211 journal_remote_server_global
->compress
,
212 journal_remote_server_global
->seal
);
216 log_warning("Failed to process data for connection %p", connection
);
218 return mhd_respondf(connection
,
219 r
, MHD_HTTP_PAYLOAD_TOO_LARGE
,
220 "Entry is too large, maximum is " STRINGIFY(DATA_SIZE_MAX
) " bytes.");
222 return mhd_respondf(connection
,
223 r
, MHD_HTTP_UNPROCESSABLE_ENTITY
,
224 "Processing failed: %m.");
231 /* The upload is finished */
233 remaining
= journal_importer_bytes_remaining(&source
->importer
);
235 log_warning("Premature EOF byte. %zu bytes lost.", remaining
);
236 return mhd_respondf(connection
,
237 0, MHD_HTTP_EXPECTATION_FAILED
,
238 "Premature EOF. %zu bytes of trailing data not processed.",
242 return mhd_respond(connection
, MHD_HTTP_ACCEPTED
, "OK.");
245 static int request_handler(
247 struct MHD_Connection
*connection
,
251 const char *upload_data
,
252 size_t *upload_data_size
,
253 void **connection_cls
) {
257 _cleanup_free_
char *hostname
= NULL
;
260 assert(connection_cls
);
264 log_trace("Handling a connection %s %s %s", method
, url
, version
);
267 return process_http_upload(connection
,
268 upload_data
, upload_data_size
,
271 if (!streq(method
, "POST"))
272 return mhd_respond(connection
, MHD_HTTP_NOT_ACCEPTABLE
, "Unsupported method.");
274 if (!streq(url
, "/upload"))
275 return mhd_respond(connection
, MHD_HTTP_NOT_FOUND
, "Not found.");
277 header
= MHD_lookup_connection_value(connection
,
278 MHD_HEADER_KIND
, "Content-Type");
279 if (!header
|| !streq(header
, "application/vnd.fdo.journal"))
280 return mhd_respond(connection
, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE
,
281 "Content-Type: application/vnd.fdo.journal is required.");
284 const union MHD_ConnectionInfo
*ci
;
286 ci
= MHD_get_connection_info(connection
,
287 MHD_CONNECTION_INFO_CONNECTION_FD
);
289 log_error("MHD_get_connection_info failed: cannot get remote fd");
290 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
291 "Cannot check remote address.");
298 if (journal_remote_server_global
->check_trust
) {
299 r
= check_permissions(connection
, &code
, &hostname
);
303 r
= getpeername_pretty(fd
, false, &hostname
);
305 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
306 "Cannot check remote hostname.");
311 r
= request_meta(connection_cls
, fd
, hostname
);
313 return respond_oom(connection
);
315 return mhd_respondf(connection
, r
, MHD_HTTP_INTERNAL_SERVER_ERROR
, "%m");
321 static int setup_microhttpd_server(RemoteServer
*s
,
326 struct MHD_OptionItem opts
[] = {
327 { MHD_OPTION_NOTIFY_COMPLETED
, (intptr_t) request_meta_free
},
328 { MHD_OPTION_EXTERNAL_LOGGER
, (intptr_t) microhttpd_logger
},
329 { MHD_OPTION_LISTEN_SOCKET
, fd
},
330 { MHD_OPTION_CONNECTION_MEMORY_LIMIT
, 128*1024},
343 const union MHD_DaemonInfo
*info
;
349 r
= fd_nonblock(fd
, true);
351 return log_error_errno(r
, "Failed to make fd:%d nonblocking: %m", fd
);
353 /* MHD_OPTION_STRICT_FOR_CLIENT is introduced in microhttpd 0.9.54,
354 * and MHD_USE_PEDANTIC_CHECKS will be deprecated in future.
355 * If MHD_USE_PEDANTIC_CHECKS is '#define'd, then it is deprecated
356 * and we should use MHD_OPTION_STRICT_FOR_CLIENT. On the other hand,
357 * if MHD_USE_PEDANTIC_CHECKS is not '#define'd, then it is not
358 * deprecated yet and there exists an enum element with the same name.
359 * So we can safely use it. */
360 #ifdef MHD_USE_PEDANTIC_CHECKS
361 opts
[opts_pos
++] = (struct MHD_OptionItem
)
362 {MHD_OPTION_STRICT_FOR_CLIENT
, 1};
364 flags
|= MHD_USE_PEDANTIC_CHECKS
;
370 opts
[opts_pos
++] = (struct MHD_OptionItem
)
371 {MHD_OPTION_HTTPS_MEM_KEY
, 0, (char*) key
};
372 opts
[opts_pos
++] = (struct MHD_OptionItem
)
373 {MHD_OPTION_HTTPS_MEM_CERT
, 0, (char*) cert
};
375 flags
|= MHD_USE_TLS
;
378 opts
[opts_pos
++] = (struct MHD_OptionItem
)
379 {MHD_OPTION_HTTPS_MEM_TRUST
, 0, (char*) trust
};
382 d
= new(MHDDaemonWrapper
, 1);
386 d
->fd
= (uint64_t) fd
;
388 d
->daemon
= MHD_start_daemon(flags
, 0,
390 request_handler
, NULL
,
391 MHD_OPTION_ARRAY
, opts
,
394 log_error("Failed to start µhttp daemon");
399 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
400 key
? "HTTPS" : "HTTP", fd
, d
);
402 info
= MHD_get_daemon_info(d
->daemon
, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY
);
404 log_error("µhttp returned NULL daemon info");
409 epoll_fd
= info
->listen_fd
;
411 log_error("µhttp epoll fd is invalid");
416 r
= sd_event_add_io(s
->events
, &d
->io_event
,
418 dispatch_http_event
, d
);
420 log_error_errno(r
, "Failed to add event callback: %m");
424 r
= sd_event_source_set_description(d
->io_event
, "io_event");
426 log_error_errno(r
, "Failed to set source name: %m");
430 r
= sd_event_add_time(s
->events
, &d
->timer_event
,
431 CLOCK_MONOTONIC
, (uint64_t) -1, 0,
432 null_timer_event_handler
, d
);
434 log_error_errno(r
, "Failed to add timer_event: %m");
438 r
= sd_event_source_set_description(d
->timer_event
, "timer_event");
440 log_error_errno(r
, "Failed to set source name: %m");
444 r
= hashmap_ensure_allocated(&s
->daemons
, &uint64_hash_ops
);
450 r
= hashmap_put(s
->daemons
, &d
->fd
, d
);
452 log_error_errno(r
, "Failed to add daemon to hashmap: %m");
460 MHD_stop_daemon(d
->daemon
);
466 static int setup_microhttpd_socket(RemoteServer
*s
,
473 fd
= make_socket_fd(LOG_DEBUG
, address
, SOCK_STREAM
, SOCK_CLOEXEC
);
477 return setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
480 static int null_timer_event_handler(sd_event_source
*timer_event
,
483 return dispatch_http_event(timer_event
, 0, 0, userdata
);
486 static int dispatch_http_event(sd_event_source
*event
,
490 MHDDaemonWrapper
*d
= userdata
;
492 MHD_UNSIGNED_LONG_LONG timeout
= ULONG_LONG_MAX
;
496 r
= MHD_run(d
->daemon
);
498 log_error("MHD_run failed!");
499 // XXX: unregister daemon
502 if (MHD_get_timeout(d
->daemon
, &timeout
) == MHD_NO
)
503 timeout
= ULONG_LONG_MAX
;
505 r
= sd_event_source_set_time(d
->timer_event
, timeout
);
507 log_warning_errno(r
, "Unable to set event loop timeout: %m, this may result in indefinite blocking!");
511 r
= sd_event_source_set_enabled(d
->timer_event
, SD_EVENT_ON
);
513 log_warning_errno(r
, "Unable to enable timer_event: %m, this may result in indefinite blocking!");
515 return 1; /* work to do */
518 /**********************************************************************
519 **********************************************************************
520 **********************************************************************/
522 static int setup_signals(RemoteServer
*s
) {
527 assert_se(sigprocmask_many(SIG_SETMASK
, NULL
, SIGINT
, SIGTERM
, -1) >= 0);
529 r
= sd_event_add_signal(s
->events
, &s
->sigterm_event
, SIGTERM
, NULL
, s
);
533 r
= sd_event_add_signal(s
->events
, &s
->sigint_event
, SIGINT
, NULL
, s
);
540 static int setup_raw_socket(RemoteServer
*s
, const char *address
) {
543 fd
= make_socket_fd(LOG_INFO
, address
, SOCK_STREAM
, SOCK_CLOEXEC
);
547 return journal_remote_add_raw_socket(s
, fd
);
550 static int create_remoteserver(
559 r
= journal_remote_server_init(s
, arg_output
, arg_split_mode
, arg_compress
, arg_seal
);
563 r
= setup_signals(s
);
565 return log_error_errno(r
, "Failed to set up signals: %m");
567 n
= sd_listen_fds(true);
569 return log_error_errno(n
, "Failed to read listening file descriptors from environment: %m");
571 log_debug("Received %d descriptors", n
);
573 if (MAX(http_socket
, https_socket
) >= SD_LISTEN_FDS_START
+ n
) {
574 log_error("Received fewer sockets than expected");
578 for (fd
= SD_LISTEN_FDS_START
; fd
< SD_LISTEN_FDS_START
+ n
; fd
++) {
579 if (sd_is_socket(fd
, AF_UNSPEC
, 0, true)) {
580 log_debug("Received a listening socket (fd:%d)", fd
);
582 if (fd
== http_socket
)
583 r
= setup_microhttpd_server(s
, fd
, NULL
, NULL
, NULL
);
584 else if (fd
== https_socket
)
585 r
= setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
587 r
= journal_remote_add_raw_socket(s
, fd
);
588 } else if (sd_is_socket(fd
, AF_UNSPEC
, 0, false)) {
591 r
= getpeername_pretty(fd
, false, &hostname
);
593 return log_error_errno(r
, "Failed to retrieve remote name: %m");
595 log_debug("Received a connection socket (fd:%d) from %s", fd
, hostname
);
597 r
= journal_remote_add_source(s
, fd
, hostname
, true);
599 log_error("Unknown socket passed on fd:%d", fd
);
605 return log_error_errno(r
, "Failed to register socket (fd:%d): %m",
610 log_info("Spawning getter %s...", arg_getter
);
611 fd
= spawn_getter(arg_getter
);
615 r
= journal_remote_add_source(s
, fd
, (char*) arg_output
, false);
624 if (!strstr(arg_url
, "/entries")) {
625 if (endswith(arg_url
, "/"))
626 url
= strjoina(arg_url
, "entries");
628 url
= strjoina(arg_url
, "/entries");
631 url
= strdupa(arg_url
);
633 log_info("Spawning curl %s...", url
);
634 fd
= spawn_curl(url
);
639 startswith(arg_url
, "https://") ?:
640 startswith(arg_url
, "http://") ?:
643 hostname
= strdupa(hostname
);
644 if ((p
= strchr(hostname
, '/')))
646 if ((p
= strchr(hostname
, ':')))
649 r
= journal_remote_add_source(s
, fd
, hostname
, false);
654 if (arg_listen_raw
) {
655 log_debug("Listening on a socket...");
656 r
= setup_raw_socket(s
, arg_listen_raw
);
661 if (arg_listen_http
) {
662 r
= setup_microhttpd_socket(s
, arg_listen_http
, NULL
, NULL
, NULL
);
667 if (arg_listen_https
) {
668 r
= setup_microhttpd_socket(s
, arg_listen_https
, key
, cert
, trust
);
673 STRV_FOREACH(file
, arg_files
) {
674 const char *output_name
;
676 if (streq(*file
, "-")) {
677 log_debug("Using standard input as source.");
680 output_name
= "stdin";
682 log_debug("Reading file %s...", *file
);
684 fd
= open(*file
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
686 return log_error_errno(errno
, "Failed to open %s: %m", *file
);
690 r
= journal_remote_add_source(s
, fd
, (char*) output_name
, false);
695 if (s
->active
== 0) {
696 log_error("Zero sources specified");
700 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
) {
701 /* In this case we know what the writer will be
702 called, so we can create it and verify that we can
703 create output as expected. */
704 r
= journal_remote_get_writer(s
, NULL
, &s
->_single_writer
);
712 static int negative_fd(const char *spec
) {
713 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
717 r
= safe_atoi(spec
, &fd
);
727 static int parse_config(void) {
728 const ConfigTableItem items
[] = {
729 { "Remote", "Seal", config_parse_bool
, 0, &arg_seal
},
730 { "Remote", "SplitMode", config_parse_write_split_mode
, 0, &arg_split_mode
},
731 { "Remote", "ServerKeyFile", config_parse_path
, 0, &arg_key
},
732 { "Remote", "ServerCertificateFile", config_parse_path
, 0, &arg_cert
},
733 { "Remote", "TrustedCertificateFile", config_parse_path
, 0, &arg_trust
},
737 return config_parse_many_nulstr(PKGSYSCONFDIR
"/journal-remote.conf",
738 CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"),
739 "Remote\0", config_item_table_lookup
, items
,
740 CONFIG_PARSE_WARN
, NULL
);
743 static int help(void) {
744 _cleanup_free_
char *link
= NULL
;
747 r
= terminal_urlify_man("systemd-journal-remote.service", "8", &link
);
751 printf("%s [OPTIONS...] {FILE|-}...\n\n"
752 "Write external journal events to journal file(s).\n\n"
753 " -h --help Show this help\n"
754 " --version Show package version\n"
755 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
756 " --getter=COMMAND Read events from the output of COMMAND\n"
757 " --listen-raw=ADDR Listen for connections at ADDR\n"
758 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
759 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
760 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
761 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
762 " --seal[=BOOL] Use event sealing (default: no)\n"
763 " --key=FILENAME SSL key in PEM format (default:\n"
764 " \"" PRIV_KEY_FILE
"\")\n"
765 " --cert=FILENAME SSL certificate in PEM format (default:\n"
766 " \"" CERT_FILE
"\")\n"
767 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
768 " \"" TRUST_FILE
"\")\n"
769 " --gnutls-log=CATEGORY...\n"
770 " Specify a list of gnutls logging categories\n"
771 " --split-mode=none|host How many output files to create\n"
772 "\nNote: file descriptors from sd_listen_fds() will be consumed, too.\n"
773 "\nSee the %s for details.\n"
774 , program_invocation_short_name
781 static int parse_argv(int argc
, char *argv
[]) {
798 static const struct option options
[] = {
799 { "help", no_argument
, NULL
, 'h' },
800 { "version", no_argument
, NULL
, ARG_VERSION
},
801 { "url", required_argument
, NULL
, ARG_URL
},
802 { "getter", required_argument
, NULL
, ARG_GETTER
},
803 { "listen-raw", required_argument
, NULL
, ARG_LISTEN_RAW
},
804 { "listen-http", required_argument
, NULL
, ARG_LISTEN_HTTP
},
805 { "listen-https", required_argument
, NULL
, ARG_LISTEN_HTTPS
},
806 { "output", required_argument
, NULL
, 'o' },
807 { "split-mode", required_argument
, NULL
, ARG_SPLIT_MODE
},
808 { "compress", optional_argument
, NULL
, ARG_COMPRESS
},
809 { "seal", optional_argument
, NULL
, ARG_SEAL
},
810 { "key", required_argument
, NULL
, ARG_KEY
},
811 { "cert", required_argument
, NULL
, ARG_CERT
},
812 { "trust", required_argument
, NULL
, ARG_TRUST
},
813 { "gnutls-log", required_argument
, NULL
, ARG_GNUTLS_LOG
},
823 while ((c
= getopt_long(argc
, argv
, "ho:", options
, NULL
)) >= 0)
834 log_error("cannot currently set more than one --url");
843 log_error("cannot currently use --getter more than once");
851 if (arg_listen_raw
) {
852 log_error("cannot currently use --listen-raw more than once");
856 arg_listen_raw
= optarg
;
859 case ARG_LISTEN_HTTP
:
860 if (arg_listen_http
|| http_socket
>= 0) {
861 log_error("cannot currently use --listen-http more than once");
865 r
= negative_fd(optarg
);
869 arg_listen_http
= optarg
;
872 case ARG_LISTEN_HTTPS
:
873 if (arg_listen_https
|| https_socket
>= 0) {
874 log_error("cannot currently use --listen-https more than once");
878 r
= negative_fd(optarg
);
882 arg_listen_https
= optarg
;
888 log_error("Key file specified twice");
892 arg_key
= strdup(optarg
);
900 log_error("Certificate file specified twice");
904 arg_cert
= strdup(optarg
);
911 if (arg_trust
|| arg_trust_all
) {
912 log_error("Confusing trusted CA configuration");
916 if (streq(optarg
, "all"))
917 arg_trust_all
= true;
920 arg_trust
= strdup(optarg
);
924 log_error("Option --trust is not available.");
933 log_error("cannot use --output/-o more than once");
941 arg_split_mode
= journal_write_split_mode_from_string(optarg
);
942 if (arg_split_mode
== _JOURNAL_WRITE_SPLIT_INVALID
) {
943 log_error("Invalid split mode: %s", optarg
);
950 r
= parse_boolean(optarg
);
952 log_error("Failed to parse --compress= parameter.");
964 r
= parse_boolean(optarg
);
966 log_error("Failed to parse --seal= parameter.");
976 case ARG_GNUTLS_LOG
: {
978 const char* p
= optarg
;
980 _cleanup_free_
char *word
= NULL
;
982 r
= extract_first_word(&p
, &word
, ",", 0);
984 return log_error_errno(r
, "Failed to parse --gnutls-log= argument: %m");
989 if (strv_push(&arg_gnutls_log
, word
) < 0)
996 log_error("Option --gnutls-log is not available.");
1005 assert_not_reached("Unknown option code.");
1009 arg_files
= argv
+ optind
;
1011 type_a
= arg_getter
|| !strv_isempty(arg_files
);
1014 || arg_listen_http
|| arg_listen_https
1015 || sd_listen_fds(false) > 0;
1016 if (type_a
&& type_b
) {
1017 log_error("Cannot use file input or --getter with "
1018 "--arg-listen-... or socket activation.");
1023 log_error("Option --output must be specified with file input or --getter.");
1027 if (!IN_SET(arg_split_mode
, JOURNAL_WRITE_SPLIT_NONE
, _JOURNAL_WRITE_SPLIT_INVALID
)) {
1028 log_error("For active sources, only --split-mode=none is allowed.");
1032 arg_split_mode
= JOURNAL_WRITE_SPLIT_NONE
;
1035 if (arg_split_mode
== _JOURNAL_WRITE_SPLIT_INVALID
)
1036 arg_split_mode
= JOURNAL_WRITE_SPLIT_HOST
;
1038 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
&& arg_output
) {
1039 if (is_dir(arg_output
, true) > 0) {
1040 log_error("For SplitMode=none, output must be a file.");
1043 if (!endswith(arg_output
, ".journal")) {
1044 log_error("For SplitMode=none, output file name must end with .journal.");
1049 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
1050 && arg_output
&& is_dir(arg_output
, true) <= 0) {
1051 log_error("For SplitMode=host, output must be a directory.");
1055 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1056 journal_write_split_mode_to_string(arg_split_mode
),
1061 return 1 /* work to do */;
1064 static int load_certificates(char **key
, char **cert
, char **trust
) {
1067 r
= read_full_file(arg_key
?: PRIV_KEY_FILE
, key
, NULL
);
1069 return log_error_errno(r
, "Failed to read key from file '%s': %m",
1070 arg_key
?: PRIV_KEY_FILE
);
1072 r
= read_full_file(arg_cert
?: CERT_FILE
, cert
, NULL
);
1074 return log_error_errno(r
, "Failed to read certificate from file '%s': %m",
1075 arg_cert
?: CERT_FILE
);
1078 log_info("Certificate checking disabled.");
1080 r
= read_full_file(arg_trust
?: TRUST_FILE
, trust
, NULL
);
1082 return log_error_errno(r
, "Failed to read CA certificate file '%s': %m",
1083 arg_trust
?: TRUST_FILE
);
1086 if ((arg_listen_raw
|| arg_listen_http
) && *trust
) {
1087 log_error("Option --trust makes all non-HTTPS connections untrusted.");
1094 int main(int argc
, char **argv
) {
1095 RemoteServer s
= {};
1097 _cleanup_free_
char *key
= NULL
, *cert
= NULL
, *trust
= NULL
;
1099 log_show_color(true);
1100 log_parse_environment();
1102 /* The journal merging logic potentially needs a lot of fds. */
1103 (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE
);
1107 return EXIT_FAILURE
;
1109 r
= parse_argv(argc
, argv
);
1111 return r
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;
1113 if (arg_listen_http
|| arg_listen_https
) {
1114 r
= setup_gnutls_logger(arg_gnutls_log
);
1116 return EXIT_FAILURE
;
1119 if (arg_listen_https
|| https_socket
>= 0) {
1120 if (load_certificates(&key
, &cert
, &trust
) < 0)
1121 return EXIT_FAILURE
;
1122 s
.check_trust
= !arg_trust_all
;
1125 if (create_remoteserver(&s
, key
, cert
, trust
) < 0)
1126 return EXIT_FAILURE
;
1128 r
= sd_event_set_watchdog(s
.events
, true);
1130 log_error_errno(r
, "Failed to enable watchdog: %m");
1132 log_debug("Watchdog is %sd.", enable_disable(r
> 0));
1134 log_debug("%s running as pid "PID_FMT
,
1135 program_invocation_short_name
, getpid_cached());
1138 "STATUS=Processing requests...");
1141 r
= sd_event_get_state(s
.events
);
1144 if (r
== SD_EVENT_FINISHED
)
1147 r
= sd_event_run(s
.events
, -1);
1149 log_error_errno(r
, "Failed to run event loop: %m");
1156 "STATUS=Shutting down after writing %" PRIu64
" entries...", s
.event_count
);
1157 log_info("Finishing after writing %" PRIu64
" entries", s
.event_count
);
1159 journal_remote_server_destroy(&s
);
1165 return r
>= 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;