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 // FIXME: unregister daemon
499 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
501 if (MHD_get_timeout(d
->daemon
, &timeout
) == MHD_NO
)
502 timeout
= ULONG_LONG_MAX
;
504 r
= sd_event_source_set_time(d
->timer_event
, timeout
);
506 log_warning_errno(r
, "Unable to set event loop timeout: %m, this may result in indefinite blocking!");
510 r
= sd_event_source_set_enabled(d
->timer_event
, SD_EVENT_ON
);
512 log_warning_errno(r
, "Unable to enable timer_event: %m, this may result in indefinite blocking!");
514 return 1; /* work to do */
517 /**********************************************************************
518 **********************************************************************
519 **********************************************************************/
521 static int setup_signals(RemoteServer
*s
) {
526 assert_se(sigprocmask_many(SIG_SETMASK
, NULL
, SIGINT
, SIGTERM
, -1) >= 0);
528 r
= sd_event_add_signal(s
->events
, &s
->sigterm_event
, SIGTERM
, NULL
, s
);
532 r
= sd_event_add_signal(s
->events
, &s
->sigint_event
, SIGINT
, NULL
, s
);
539 static int setup_raw_socket(RemoteServer
*s
, const char *address
) {
542 fd
= make_socket_fd(LOG_INFO
, address
, SOCK_STREAM
, SOCK_CLOEXEC
);
546 return journal_remote_add_raw_socket(s
, fd
);
549 static int create_remoteserver(
558 r
= journal_remote_server_init(s
, arg_output
, arg_split_mode
, arg_compress
, arg_seal
);
562 r
= setup_signals(s
);
564 return log_error_errno(r
, "Failed to set up signals: %m");
566 n
= sd_listen_fds(true);
568 return log_error_errno(n
, "Failed to read listening file descriptors from environment: %m");
570 log_debug("Received %d descriptors", n
);
572 if (MAX(http_socket
, https_socket
) >= SD_LISTEN_FDS_START
+ n
)
573 return log_error_errno(SYNTHETIC_ERRNO(EBADFD
),
574 "Received fewer sockets than expected");
576 for (fd
= SD_LISTEN_FDS_START
; fd
< SD_LISTEN_FDS_START
+ n
; fd
++) {
577 if (sd_is_socket(fd
, AF_UNSPEC
, 0, true)) {
578 log_debug("Received a listening socket (fd:%d)", fd
);
580 if (fd
== http_socket
)
581 r
= setup_microhttpd_server(s
, fd
, NULL
, NULL
, NULL
);
582 else if (fd
== https_socket
)
583 r
= setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
585 r
= journal_remote_add_raw_socket(s
, fd
);
586 } else if (sd_is_socket(fd
, AF_UNSPEC
, 0, false)) {
589 r
= getpeername_pretty(fd
, false, &hostname
);
591 return log_error_errno(r
, "Failed to retrieve remote name: %m");
593 log_debug("Received a connection socket (fd:%d) from %s", fd
, hostname
);
595 r
= journal_remote_add_source(s
, fd
, hostname
, true);
597 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
598 "Unknown socket passed on fd:%d", fd
);
601 return log_error_errno(r
, "Failed to register socket (fd:%d): %m", fd
);
605 log_info("Spawning getter %s...", arg_getter
);
606 fd
= spawn_getter(arg_getter
);
610 r
= journal_remote_add_source(s
, fd
, (char*) arg_output
, false);
619 if (!strstr(arg_url
, "/entries")) {
620 if (endswith(arg_url
, "/"))
621 url
= strjoina(arg_url
, "entries");
623 url
= strjoina(arg_url
, "/entries");
625 url
= strdupa(arg_url
);
627 log_info("Spawning curl %s...", url
);
628 fd
= spawn_curl(url
);
632 hostname
= STARTSWITH_SET(arg_url
, "https://", "http://");
636 hostname
= strndupa(hostname
, strcspn(hostname
, "/:"));
638 r
= journal_remote_add_source(s
, fd
, hostname
, false);
643 if (arg_listen_raw
) {
644 log_debug("Listening on a socket...");
645 r
= setup_raw_socket(s
, arg_listen_raw
);
650 if (arg_listen_http
) {
651 r
= setup_microhttpd_socket(s
, arg_listen_http
, NULL
, NULL
, NULL
);
656 if (arg_listen_https
) {
657 r
= setup_microhttpd_socket(s
, arg_listen_https
, key
, cert
, trust
);
662 STRV_FOREACH(file
, arg_files
) {
663 const char *output_name
;
665 if (streq(*file
, "-")) {
666 log_debug("Using standard input as source.");
669 output_name
= "stdin";
671 log_debug("Reading file %s...", *file
);
673 fd
= open(*file
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
675 return log_error_errno(errno
, "Failed to open %s: %m", *file
);
679 r
= journal_remote_add_source(s
, fd
, (char*) output_name
, false);
685 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
686 "Zero sources specified");
688 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
) {
689 /* In this case we know what the writer will be
690 called, so we can create it and verify that we can
691 create output as expected. */
692 r
= journal_remote_get_writer(s
, NULL
, &s
->_single_writer
);
700 static int negative_fd(const char *spec
) {
701 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
705 r
= safe_atoi(spec
, &fd
);
715 static int parse_config(void) {
716 const ConfigTableItem items
[] = {
717 { "Remote", "Seal", config_parse_bool
, 0, &arg_seal
},
718 { "Remote", "SplitMode", config_parse_write_split_mode
, 0, &arg_split_mode
},
719 { "Remote", "ServerKeyFile", config_parse_path
, 0, &arg_key
},
720 { "Remote", "ServerCertificateFile", config_parse_path
, 0, &arg_cert
},
721 { "Remote", "TrustedCertificateFile", config_parse_path
, 0, &arg_trust
},
725 return config_parse_many_nulstr(PKGSYSCONFDIR
"/journal-remote.conf",
726 CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"),
727 "Remote\0", config_item_table_lookup
, items
,
728 CONFIG_PARSE_WARN
, NULL
);
731 static int help(void) {
732 _cleanup_free_
char *link
= NULL
;
735 r
= terminal_urlify_man("systemd-journal-remote.service", "8", &link
);
739 printf("%s [OPTIONS...] {FILE|-}...\n\n"
740 "Write external journal events to journal file(s).\n\n"
741 " -h --help Show this help\n"
742 " --version Show package version\n"
743 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
744 " --getter=COMMAND Read events from the output of COMMAND\n"
745 " --listen-raw=ADDR Listen for connections at ADDR\n"
746 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
747 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
748 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
749 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
750 " --seal[=BOOL] Use event sealing (default: no)\n"
751 " --key=FILENAME SSL key in PEM format (default:\n"
752 " \"" PRIV_KEY_FILE
"\")\n"
753 " --cert=FILENAME SSL certificate in PEM format (default:\n"
754 " \"" CERT_FILE
"\")\n"
755 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
756 " \"" TRUST_FILE
"\")\n"
757 " --gnutls-log=CATEGORY...\n"
758 " Specify a list of gnutls logging categories\n"
759 " --split-mode=none|host How many output files to create\n"
760 "\nNote: file descriptors from sd_listen_fds() will be consumed, too.\n"
761 "\nSee the %s for details.\n"
762 , program_invocation_short_name
769 static int parse_argv(int argc
, char *argv
[]) {
786 static const struct option options
[] = {
787 { "help", no_argument
, NULL
, 'h' },
788 { "version", no_argument
, NULL
, ARG_VERSION
},
789 { "url", required_argument
, NULL
, ARG_URL
},
790 { "getter", required_argument
, NULL
, ARG_GETTER
},
791 { "listen-raw", required_argument
, NULL
, ARG_LISTEN_RAW
},
792 { "listen-http", required_argument
, NULL
, ARG_LISTEN_HTTP
},
793 { "listen-https", required_argument
, NULL
, ARG_LISTEN_HTTPS
},
794 { "output", required_argument
, NULL
, 'o' },
795 { "split-mode", required_argument
, NULL
, ARG_SPLIT_MODE
},
796 { "compress", optional_argument
, NULL
, ARG_COMPRESS
},
797 { "seal", optional_argument
, NULL
, ARG_SEAL
},
798 { "key", required_argument
, NULL
, ARG_KEY
},
799 { "cert", required_argument
, NULL
, ARG_CERT
},
800 { "trust", required_argument
, NULL
, ARG_TRUST
},
801 { "gnutls-log", required_argument
, NULL
, ARG_GNUTLS_LOG
},
811 while ((c
= getopt_long(argc
, argv
, "ho:", options
, NULL
)) >= 0)
822 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
823 "cannot currently set more than one --url");
830 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
831 "cannot currently use --getter more than once");
838 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
839 "cannot currently use --listen-raw more than once");
841 arg_listen_raw
= optarg
;
844 case ARG_LISTEN_HTTP
:
845 if (arg_listen_http
|| http_socket
>= 0)
846 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
847 "cannot currently use --listen-http more than once");
849 r
= negative_fd(optarg
);
853 arg_listen_http
= optarg
;
856 case ARG_LISTEN_HTTPS
:
857 if (arg_listen_https
|| https_socket
>= 0)
858 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
859 "cannot currently use --listen-https more than once");
861 r
= negative_fd(optarg
);
865 arg_listen_https
= optarg
;
871 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
872 "Key file specified twice");
874 arg_key
= strdup(optarg
);
882 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
883 "Certificate file specified twice");
885 arg_cert
= strdup(optarg
);
892 if (arg_trust
|| arg_trust_all
)
893 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
894 "Confusing trusted CA configuration");
896 if (streq(optarg
, "all"))
897 arg_trust_all
= true;
900 arg_trust
= strdup(optarg
);
904 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
905 "Option --trust is not available.");
913 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
914 "cannot use --output/-o more than once");
920 arg_split_mode
= journal_write_split_mode_from_string(optarg
);
921 if (arg_split_mode
== _JOURNAL_WRITE_SPLIT_INVALID
)
922 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
923 "Invalid split mode: %s", optarg
);
928 r
= parse_boolean(optarg
);
930 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
931 "Failed to parse --compress= parameter.");
941 r
= parse_boolean(optarg
);
943 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
944 "Failed to parse --seal= parameter.");
952 case ARG_GNUTLS_LOG
: {
954 const char* p
= optarg
;
956 _cleanup_free_
char *word
= NULL
;
958 r
= extract_first_word(&p
, &word
, ",", 0);
960 return log_error_errno(r
, "Failed to parse --gnutls-log= argument: %m");
964 if (strv_push(&arg_gnutls_log
, word
) < 0)
971 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
972 "Option --gnutls-log is not available.");
980 assert_not_reached("Unknown option code.");
984 arg_files
= argv
+ optind
;
986 type_a
= arg_getter
|| !strv_isempty(arg_files
);
989 || arg_listen_http
|| arg_listen_https
990 || sd_listen_fds(false) > 0;
991 if (type_a
&& type_b
)
992 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
993 "Cannot use file input or --getter with "
994 "--arg-listen-... or socket activation.");
997 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
998 "Option --output must be specified with file input or --getter.");
1000 if (!IN_SET(arg_split_mode
, JOURNAL_WRITE_SPLIT_NONE
, _JOURNAL_WRITE_SPLIT_INVALID
))
1001 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1002 "For active sources, only --split-mode=none is allowed.");
1004 arg_split_mode
= JOURNAL_WRITE_SPLIT_NONE
;
1007 if (arg_split_mode
== _JOURNAL_WRITE_SPLIT_INVALID
)
1008 arg_split_mode
= JOURNAL_WRITE_SPLIT_HOST
;
1010 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
&& arg_output
) {
1011 if (is_dir(arg_output
, true) > 0)
1012 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1013 "For SplitMode=none, output must be a file.");
1014 if (!endswith(arg_output
, ".journal"))
1015 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1016 "For SplitMode=none, output file name must end with .journal.");
1019 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
1020 && arg_output
&& is_dir(arg_output
, true) <= 0)
1021 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1022 "For SplitMode=host, output must be a directory.");
1024 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1025 journal_write_split_mode_to_string(arg_split_mode
),
1030 return 1 /* work to do */;
1033 static int load_certificates(char **key
, char **cert
, char **trust
) {
1036 r
= read_full_file(arg_key
?: PRIV_KEY_FILE
, key
, NULL
);
1038 return log_error_errno(r
, "Failed to read key from file '%s': %m",
1039 arg_key
?: PRIV_KEY_FILE
);
1041 r
= read_full_file(arg_cert
?: CERT_FILE
, cert
, NULL
);
1043 return log_error_errno(r
, "Failed to read certificate from file '%s': %m",
1044 arg_cert
?: CERT_FILE
);
1047 log_info("Certificate checking disabled.");
1049 r
= read_full_file(arg_trust
?: TRUST_FILE
, trust
, NULL
);
1051 return log_error_errno(r
, "Failed to read CA certificate file '%s': %m",
1052 arg_trust
?: TRUST_FILE
);
1055 if ((arg_listen_raw
|| arg_listen_http
) && *trust
)
1056 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1057 "Option --trust makes all non-HTTPS connections untrusted.");
1062 int main(int argc
, char **argv
) {
1063 RemoteServer s
= {};
1065 _cleanup_free_
char *key
= NULL
, *cert
= NULL
, *trust
= NULL
;
1067 log_show_color(true);
1068 log_parse_environment();
1070 /* The journal merging logic potentially needs a lot of fds. */
1071 (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE
);
1075 return EXIT_FAILURE
;
1077 r
= parse_argv(argc
, argv
);
1079 return r
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;
1081 if (arg_listen_http
|| arg_listen_https
) {
1082 r
= setup_gnutls_logger(arg_gnutls_log
);
1084 return EXIT_FAILURE
;
1087 if (arg_listen_https
|| https_socket
>= 0) {
1088 if (load_certificates(&key
, &cert
, &trust
) < 0)
1089 return EXIT_FAILURE
;
1090 s
.check_trust
= !arg_trust_all
;
1093 if (create_remoteserver(&s
, key
, cert
, trust
) < 0)
1094 return EXIT_FAILURE
;
1096 r
= sd_event_set_watchdog(s
.events
, true);
1098 log_error_errno(r
, "Failed to enable watchdog: %m");
1100 log_debug("Watchdog is %sd.", enable_disable(r
> 0));
1102 log_debug("%s running as pid "PID_FMT
,
1103 program_invocation_short_name
, getpid_cached());
1106 "STATUS=Processing requests...");
1109 r
= sd_event_get_state(s
.events
);
1112 if (r
== SD_EVENT_FINISHED
)
1115 r
= sd_event_run(s
.events
, -1);
1117 log_error_errno(r
, "Failed to run event loop: %m");
1124 "STATUS=Shutting down after writing %" PRIu64
" entries...", s
.event_count
);
1125 log_info("Finishing after writing %" PRIu64
" entries", s
.event_count
);
1127 journal_remote_server_destroy(&s
);
1133 return r
>= 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;