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>
33 #include <gnutls/gnutls.h>
36 #include "sd-daemon.h"
38 #include "conf-parser.h"
41 #include "journal-file.h"
42 #include "journal-remote-write.h"
43 #include "journald-native.h"
45 #include "signal-util.h"
46 #include "socket-util.h"
47 #include "string-util.h"
49 #include "journal-remote.h"
51 #define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
53 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
54 #define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
55 #define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
57 static char* arg_url
= NULL
;
58 static char* arg_getter
= NULL
;
59 static char* arg_listen_raw
= NULL
;
60 static char* arg_listen_http
= NULL
;
61 static char* arg_listen_https
= NULL
;
62 static char** arg_files
= NULL
;
63 static int arg_compress
= true;
64 static int arg_seal
= false;
65 static int http_socket
= -1, https_socket
= -1;
66 static char** arg_gnutls_log
= NULL
;
68 static JournalWriteSplitMode arg_split_mode
= JOURNAL_WRITE_SPLIT_HOST
;
69 static char* arg_output
= NULL
;
71 static char *arg_key
= NULL
;
72 static char *arg_cert
= NULL
;
73 static char *arg_trust
= NULL
;
74 static bool arg_trust_all
= false;
76 /**********************************************************************
77 **********************************************************************
78 **********************************************************************/
80 static int spawn_child(const char* child
, char** argv
) {
82 pid_t parent_pid
, child_pid
;
86 return log_error_errno(errno
, "Failed to create pager pipe: %m");
88 parent_pid
= getpid();
92 r
= log_error_errno(errno
, "Failed to fork: %m");
100 (void) reset_all_signal_handlers();
101 (void) reset_signal_mask();
103 r
= dup2(fd
[1], STDOUT_FILENO
);
105 log_error_errno(errno
, "Failed to dup pipe to stdout: %m");
111 /* Make sure the child goes away when the parent dies */
112 if (prctl(PR_SET_PDEATHSIG
, SIGTERM
) < 0)
115 /* Check whether our parent died before we were able
116 * to set the death signal */
117 if (getppid() != parent_pid
)
121 log_error_errno(errno
, "Failed to exec child %s: %m", child
);
127 log_warning_errno(errno
, "Failed to close write end of pipe: %m");
132 static int spawn_curl(const char* url
) {
133 char **argv
= STRV_MAKE("curl",
134 "-HAccept: application/vnd.fdo.journal",
140 r
= spawn_child("curl", argv
);
142 log_error_errno(errno
, "Failed to spawn curl: %m");
146 static int spawn_getter(const char *getter
, const char *url
) {
148 _cleanup_strv_free_
char **words
= NULL
;
151 r
= strv_split_extract(&words
, getter
, WHITESPACE
, EXTRACT_QUOTES
);
153 return log_error_errno(r
, "Failed to split getter option: %m");
155 r
= strv_extend(&words
, url
);
157 return log_error_errno(r
, "Failed to create command line: %m");
159 r
= spawn_child(words
[0], words
);
161 log_error_errno(errno
, "Failed to spawn getter %s: %m", getter
);
166 #define filename_escape(s) xescape((s), "/ ")
168 static int open_output(Writer
*w
, const char* host
) {
169 _cleanup_free_
char *_output
= NULL
;
173 switch (arg_split_mode
) {
174 case JOURNAL_WRITE_SPLIT_NONE
:
175 output
= arg_output
?: REMOTE_JOURNAL_PATH
"/remote.journal";
178 case JOURNAL_WRITE_SPLIT_HOST
: {
179 _cleanup_free_
char *name
;
183 name
= filename_escape(host
);
187 r
= asprintf(&_output
, "%s/remote-%s.journal",
188 arg_output
?: REMOTE_JOURNAL_PATH
,
198 assert_not_reached("what?");
201 r
= journal_file_open_reliably(output
,
202 O_RDWR
|O_CREAT
, 0640,
203 arg_compress
, arg_seal
,
208 log_error_errno(r
, "Failed to open output journal %s: %m",
211 log_debug("Opened output file %s", w
->journal
->path
);
215 /**********************************************************************
216 **********************************************************************
217 **********************************************************************/
219 static int init_writer_hashmap(RemoteServer
*s
) {
220 static const struct hash_ops
*hash_ops
[] = {
221 [JOURNAL_WRITE_SPLIT_NONE
] = NULL
,
222 [JOURNAL_WRITE_SPLIT_HOST
] = &string_hash_ops
,
225 assert(arg_split_mode
>= 0 && arg_split_mode
< (int) ELEMENTSOF(hash_ops
));
227 s
->writers
= hashmap_new(hash_ops
[arg_split_mode
]);
234 static int get_writer(RemoteServer
*s
, const char *host
,
237 _cleanup_writer_unref_ Writer
*w
= NULL
;
240 switch(arg_split_mode
) {
241 case JOURNAL_WRITE_SPLIT_NONE
:
242 key
= "one and only";
245 case JOURNAL_WRITE_SPLIT_HOST
:
251 assert_not_reached("what split mode?");
254 w
= hashmap_get(s
->writers
, key
);
262 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
) {
263 w
->hashmap_key
= strdup(key
);
268 r
= open_output(w
, host
);
272 r
= hashmap_put(s
->writers
, w
->hashmap_key
?: key
, w
);
282 /**********************************************************************
283 **********************************************************************
284 **********************************************************************/
286 /* This should go away as soon as µhttpd allows state to be passed around. */
287 static RemoteServer
*server
;
289 static int dispatch_raw_source_event(sd_event_source
*event
,
293 static int dispatch_raw_source_until_block(sd_event_source
*event
,
295 static int dispatch_blocking_source_event(sd_event_source
*event
,
297 static int dispatch_raw_connection_event(sd_event_source
*event
,
301 static int dispatch_http_event(sd_event_source
*event
,
306 static int get_source_for_fd(RemoteServer
*s
,
307 int fd
, char *name
, RemoteSource
**source
) {
311 /* This takes ownership of name, but only on success. */
316 if (!GREEDY_REALLOC0(s
->sources
, s
->sources_size
, fd
+ 1))
319 r
= get_writer(s
, name
, &writer
);
321 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
324 if (s
->sources
[fd
] == NULL
) {
325 s
->sources
[fd
] = source_new(fd
, false, name
, writer
);
326 if (!s
->sources
[fd
]) {
327 writer_unref(writer
);
334 *source
= s
->sources
[fd
];
338 static int remove_source(RemoteServer
*s
, int fd
) {
339 RemoteSource
*source
;
342 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
344 source
= s
->sources
[fd
];
346 /* this closes fd too */
348 s
->sources
[fd
] = NULL
;
355 static int add_source(RemoteServer
*s
, int fd
, char* name
, bool own_name
) {
357 RemoteSource
*source
= NULL
;
360 /* This takes ownership of name, even on failure, if own_name is true. */
372 r
= get_source_for_fd(s
, fd
, name
, &source
);
374 log_error_errno(r
, "Failed to create source for fd:%d (%s): %m",
380 r
= sd_event_add_io(s
->events
, &source
->event
,
381 fd
, EPOLLIN
|EPOLLRDHUP
|EPOLLPRI
,
382 dispatch_raw_source_event
, source
);
384 /* Add additional source for buffer processing. It will be
386 r
= sd_event_add_defer(s
->events
, &source
->buffer_event
,
387 dispatch_raw_source_until_block
, source
);
389 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_OFF
);
390 } else if (r
== -EPERM
) {
391 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd
, name
);
392 r
= sd_event_add_defer(s
->events
, &source
->event
,
393 dispatch_blocking_source_event
, source
);
395 sd_event_source_set_enabled(source
->event
, SD_EVENT_ON
);
398 log_error_errno(r
, "Failed to register event source for fd:%d: %m",
403 r
= sd_event_source_set_description(source
->event
, name
);
405 log_error_errno(r
, "Failed to set source name for fd:%d: %m", fd
);
409 return 1; /* work to do */
412 remove_source(s
, fd
);
416 static int add_raw_socket(RemoteServer
*s
, int fd
) {
418 _cleanup_close_
int fd_
= fd
;
419 char name
[sizeof("raw-socket-")-1 + DECIMAL_STR_MAX(int) + 1];
423 r
= sd_event_add_io(s
->events
, &s
->listen_event
,
425 dispatch_raw_connection_event
, s
);
429 xsprintf(name
, "raw-socket-%d", fd
);
431 r
= sd_event_source_set_description(s
->listen_event
, name
);
440 static int setup_raw_socket(RemoteServer
*s
, const char *address
) {
443 fd
= make_socket_fd(LOG_INFO
, address
, SOCK_STREAM
| SOCK_CLOEXEC
);
447 return add_raw_socket(s
, fd
);
450 /**********************************************************************
451 **********************************************************************
452 **********************************************************************/
454 static int request_meta(void **connection_cls
, int fd
, char *hostname
) {
455 RemoteSource
*source
;
459 assert(connection_cls
);
463 r
= get_writer(server
, hostname
, &writer
);
465 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
468 source
= source_new(fd
, true, hostname
, writer
);
470 writer_unref(writer
);
474 log_debug("Added RemoteSource as connection metadata %p", source
);
476 *connection_cls
= source
;
480 static void request_meta_free(void *cls
,
481 struct MHD_Connection
*connection
,
482 void **connection_cls
,
483 enum MHD_RequestTerminationCode toe
) {
486 assert(connection_cls
);
490 log_debug("Cleaning up connection metadata %p", s
);
492 *connection_cls
= NULL
;
496 static int process_http_upload(
497 struct MHD_Connection
*connection
,
498 const char *upload_data
,
499 size_t *upload_data_size
,
500 RemoteSource
*source
) {
502 bool finished
= false;
508 log_trace("%s: connection %p, %zu bytes",
509 __func__
, connection
, *upload_data_size
);
511 if (*upload_data_size
) {
512 log_trace("Received %zu bytes", *upload_data_size
);
514 r
= push_data(source
, upload_data
, *upload_data_size
);
516 return mhd_respond_oom(connection
);
518 *upload_data_size
= 0;
523 r
= process_source(source
, arg_compress
, arg_seal
);
527 log_warning("Failed to process data for connection %p", connection
);
529 return mhd_respondf(connection
,
530 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
,
531 "Entry is too large, maximum is %u bytes.\n",
534 return mhd_respondf(connection
,
535 MHD_HTTP_UNPROCESSABLE_ENTITY
,
536 "Processing failed: %s.", strerror(-r
));
543 /* The upload is finished */
545 remaining
= source_non_empty(source
);
547 log_warning("Premature EOFbyte. %zu bytes lost.", remaining
);
548 return mhd_respondf(connection
, MHD_HTTP_EXPECTATION_FAILED
,
549 "Premature EOF. %zu bytes of trailing data not processed.",
553 return mhd_respond(connection
, MHD_HTTP_ACCEPTED
, "OK.\n");
556 static int request_handler(
558 struct MHD_Connection
*connection
,
562 const char *upload_data
,
563 size_t *upload_data_size
,
564 void **connection_cls
) {
568 _cleanup_free_
char *hostname
= NULL
;
571 assert(connection_cls
);
575 log_trace("Handling a connection %s %s %s", method
, url
, version
);
578 return process_http_upload(connection
,
579 upload_data
, upload_data_size
,
582 if (!streq(method
, "POST"))
583 return mhd_respond(connection
, MHD_HTTP_METHOD_NOT_ACCEPTABLE
,
584 "Unsupported method.\n");
586 if (!streq(url
, "/upload"))
587 return mhd_respond(connection
, MHD_HTTP_NOT_FOUND
,
590 header
= MHD_lookup_connection_value(connection
,
591 MHD_HEADER_KIND
, "Content-Type");
592 if (!header
|| !streq(header
, "application/vnd.fdo.journal"))
593 return mhd_respond(connection
, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE
,
594 "Content-Type: application/vnd.fdo.journal"
598 const union MHD_ConnectionInfo
*ci
;
600 ci
= MHD_get_connection_info(connection
,
601 MHD_CONNECTION_INFO_CONNECTION_FD
);
603 log_error("MHD_get_connection_info failed: cannot get remote fd");
604 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
605 "Cannot check remote address");
612 if (server
->check_trust
) {
613 r
= check_permissions(connection
, &code
, &hostname
);
617 r
= getnameinfo_pretty(fd
, &hostname
);
619 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
620 "Cannot check remote hostname");
625 r
= request_meta(connection_cls
, fd
, hostname
);
627 return respond_oom(connection
);
629 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
636 static int setup_microhttpd_server(RemoteServer
*s
,
641 struct MHD_OptionItem opts
[] = {
642 { MHD_OPTION_NOTIFY_COMPLETED
, (intptr_t) request_meta_free
},
643 { MHD_OPTION_EXTERNAL_LOGGER
, (intptr_t) microhttpd_logger
},
644 { MHD_OPTION_LISTEN_SOCKET
, fd
},
653 MHD_USE_EPOLL_LINUX_ONLY
|
654 MHD_USE_PEDANTIC_CHECKS
|
655 MHD_USE_PIPE_FOR_SHUTDOWN
;
657 const union MHD_DaemonInfo
*info
;
663 r
= fd_nonblock(fd
, true);
665 return log_error_errno(r
, "Failed to make fd:%d nonblocking: %m", fd
);
670 opts
[opts_pos
++] = (struct MHD_OptionItem
)
671 {MHD_OPTION_HTTPS_MEM_KEY
, 0, (char*) key
};
672 opts
[opts_pos
++] = (struct MHD_OptionItem
)
673 {MHD_OPTION_HTTPS_MEM_CERT
, 0, (char*) cert
};
675 flags
|= MHD_USE_SSL
;
678 opts
[opts_pos
++] = (struct MHD_OptionItem
)
679 {MHD_OPTION_HTTPS_MEM_TRUST
, 0, (char*) trust
};
682 d
= new(MHDDaemonWrapper
, 1);
686 d
->fd
= (uint64_t) fd
;
688 d
->daemon
= MHD_start_daemon(flags
, 0,
690 request_handler
, NULL
,
691 MHD_OPTION_ARRAY
, opts
,
694 log_error("Failed to start µhttp daemon");
699 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
700 key
? "HTTPS" : "HTTP", fd
, d
);
703 info
= MHD_get_daemon_info(d
->daemon
, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY
);
705 log_error("µhttp returned NULL daemon info");
710 epoll_fd
= info
->listen_fd
;
712 log_error("µhttp epoll fd is invalid");
717 r
= sd_event_add_io(s
->events
, &d
->event
,
719 dispatch_http_event
, d
);
721 log_error_errno(r
, "Failed to add event callback: %m");
725 r
= sd_event_source_set_description(d
->event
, "epoll-fd");
727 log_error_errno(r
, "Failed to set source name: %m");
731 r
= hashmap_ensure_allocated(&s
->daemons
, &uint64_hash_ops
);
737 r
= hashmap_put(s
->daemons
, &d
->fd
, d
);
739 log_error_errno(r
, "Failed to add daemon to hashmap: %m");
747 MHD_stop_daemon(d
->daemon
);
753 static int setup_microhttpd_socket(RemoteServer
*s
,
760 fd
= make_socket_fd(LOG_DEBUG
, address
, SOCK_STREAM
| SOCK_CLOEXEC
);
764 return setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
767 static int dispatch_http_event(sd_event_source
*event
,
771 MHDDaemonWrapper
*d
= userdata
;
776 r
= MHD_run(d
->daemon
);
778 log_error("MHD_run failed!");
779 // XXX: unregister daemon
783 return 1; /* work to do */
786 /**********************************************************************
787 **********************************************************************
788 **********************************************************************/
790 static int setup_signals(RemoteServer
*s
) {
795 assert_se(sigprocmask_many(SIG_SETMASK
, NULL
, SIGINT
, SIGTERM
, -1) >= 0);
797 r
= sd_event_add_signal(s
->events
, &s
->sigterm_event
, SIGTERM
, NULL
, s
);
801 r
= sd_event_add_signal(s
->events
, &s
->sigint_event
, SIGINT
, NULL
, s
);
808 static int negative_fd(const char *spec
) {
809 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
813 r
= safe_atoi(spec
, &fd
);
823 static int remoteserver_init(RemoteServer
*s
,
832 if ((arg_listen_raw
|| arg_listen_http
) && trust
) {
833 log_error("Option --trust makes all non-HTTPS connections untrusted.");
837 r
= sd_event_default(&s
->events
);
839 return log_error_errno(r
, "Failed to allocate event loop: %m");
843 assert(server
== NULL
);
846 r
= init_writer_hashmap(s
);
850 n
= sd_listen_fds(true);
852 return log_error_errno(n
, "Failed to read listening file descriptors from environment: %m");
854 log_debug("Received %d descriptors", n
);
856 if (MAX(http_socket
, https_socket
) >= SD_LISTEN_FDS_START
+ n
) {
857 log_error("Received fewer sockets than expected");
861 for (fd
= SD_LISTEN_FDS_START
; fd
< SD_LISTEN_FDS_START
+ n
; fd
++) {
862 if (sd_is_socket(fd
, AF_UNSPEC
, 0, true)) {
863 log_debug("Received a listening socket (fd:%d)", fd
);
865 if (fd
== http_socket
)
866 r
= setup_microhttpd_server(s
, fd
, NULL
, NULL
, NULL
);
867 else if (fd
== https_socket
)
868 r
= setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
870 r
= add_raw_socket(s
, fd
);
871 } else if (sd_is_socket(fd
, AF_UNSPEC
, 0, false)) {
874 r
= getnameinfo_pretty(fd
, &hostname
);
876 return log_error_errno(r
, "Failed to retrieve remote name: %m");
878 log_debug("Received a connection socket (fd:%d) from %s", fd
, hostname
);
880 r
= add_source(s
, fd
, hostname
, true);
882 log_error("Unknown socket passed on fd:%d", fd
);
888 return log_error_errno(r
, "Failed to register socket (fd:%d): %m",
893 const char *url
, *hostname
;
895 url
= strjoina(arg_url
, "/entries");
898 log_info("Spawning getter %s...", url
);
899 fd
= spawn_getter(arg_getter
, url
);
901 log_info("Spawning curl %s...", url
);
902 fd
= spawn_curl(url
);
908 startswith(arg_url
, "https://") ?:
909 startswith(arg_url
, "http://") ?:
912 r
= add_source(s
, fd
, (char*) hostname
, false);
917 if (arg_listen_raw
) {
918 log_debug("Listening on a socket...");
919 r
= setup_raw_socket(s
, arg_listen_raw
);
924 if (arg_listen_http
) {
925 r
= setup_microhttpd_socket(s
, arg_listen_http
, NULL
, NULL
, NULL
);
930 if (arg_listen_https
) {
931 r
= setup_microhttpd_socket(s
, arg_listen_https
, key
, cert
, trust
);
936 STRV_FOREACH(file
, arg_files
) {
937 const char *output_name
;
939 if (streq(*file
, "-")) {
940 log_debug("Using standard input as source.");
943 output_name
= "stdin";
945 log_debug("Reading file %s...", *file
);
947 fd
= open(*file
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
949 return log_error_errno(errno
, "Failed to open %s: %m", *file
);
953 r
= add_source(s
, fd
, (char*) output_name
, false);
958 if (s
->active
== 0) {
959 log_error("Zero sources specified");
963 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
) {
964 /* In this case we know what the writer will be
965 called, so we can create it and verify that we can
966 create output as expected. */
967 r
= get_writer(s
, NULL
, &s
->_single_writer
);
975 static void server_destroy(RemoteServer
*s
) {
979 while ((d
= hashmap_steal_first(s
->daemons
))) {
980 MHD_stop_daemon(d
->daemon
);
981 sd_event_source_unref(d
->event
);
985 hashmap_free(s
->daemons
);
987 assert(s
->sources_size
== 0 || s
->sources
);
988 for (i
= 0; i
< s
->sources_size
; i
++)
992 writer_unref(s
->_single_writer
);
993 hashmap_free(s
->writers
);
995 sd_event_source_unref(s
->sigterm_event
);
996 sd_event_source_unref(s
->sigint_event
);
997 sd_event_source_unref(s
->listen_event
);
998 sd_event_unref(s
->events
);
1000 /* fds that we're listening on remain open... */
1003 /**********************************************************************
1004 **********************************************************************
1005 **********************************************************************/
1007 static int handle_raw_source(sd_event_source
*event
,
1012 RemoteSource
*source
;
1015 /* Returns 1 if there might be more data pending,
1016 * 0 if data is currently exhausted, negative on error.
1019 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
1020 source
= s
->sources
[fd
];
1021 assert(source
->fd
== fd
);
1023 r
= process_source(source
, arg_compress
, arg_seal
);
1024 if (source
->state
== STATE_EOF
) {
1027 log_debug("EOF reached with source fd:%d (%s)",
1028 source
->fd
, source
->name
);
1030 remaining
= source_non_empty(source
);
1032 log_notice("Premature EOF. %zu bytes lost.", remaining
);
1033 remove_source(s
, source
->fd
);
1034 log_debug("%zu active sources remaining", s
->active
);
1036 } else if (r
== -E2BIG
) {
1037 log_notice_errno(E2BIG
, "Entry too big, skipped");
1039 } else if (r
== -EAGAIN
) {
1042 log_debug_errno(r
, "Closing connection: %m");
1043 remove_source(server
, fd
);
1049 static int dispatch_raw_source_until_block(sd_event_source
*event
,
1051 RemoteSource
*source
= userdata
;
1054 /* Make sure event stays around even if source is destroyed */
1055 sd_event_source_ref(event
);
1057 r
= handle_raw_source(event
, source
->fd
, EPOLLIN
, server
);
1059 /* No more data for now */
1060 sd_event_source_set_enabled(event
, SD_EVENT_OFF
);
1062 sd_event_source_unref(event
);
1067 static int dispatch_raw_source_event(sd_event_source
*event
,
1071 RemoteSource
*source
= userdata
;
1074 assert(source
->event
);
1075 assert(source
->buffer_event
);
1077 r
= handle_raw_source(event
, fd
, EPOLLIN
, server
);
1079 /* Might have more data. We need to rerun the handler
1080 * until we are sure the buffer is exhausted. */
1081 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_ON
);
1086 static int dispatch_blocking_source_event(sd_event_source
*event
,
1088 RemoteSource
*source
= userdata
;
1090 return handle_raw_source(event
, source
->fd
, EPOLLIN
, server
);
1093 static int accept_connection(const char* type
, int fd
,
1094 SocketAddress
*addr
, char **hostname
) {
1097 log_debug("Accepting new %s connection on fd:%d", type
, fd
);
1098 fd2
= accept4(fd
, &addr
->sockaddr
.sa
, &addr
->size
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
1100 return log_error_errno(errno
, "accept() on fd:%d failed: %m", fd
);
1102 switch(socket_address_family(addr
)) {
1105 _cleanup_free_
char *a
= NULL
;
1108 r
= socket_address_print(addr
, &a
);
1110 log_error_errno(r
, "socket_address_print(): %m");
1115 r
= socknameinfo_pretty(&addr
->sockaddr
, addr
->size
, &b
);
1117 log_error_errno(r
, "Resolving hostname failed: %m");
1122 log_debug("Accepted %s %s connection from %s",
1124 socket_address_family(addr
) == AF_INET
? "IP" : "IPv6",
1132 log_error("Rejected %s connection with unsupported family %d",
1133 type
, socket_address_family(addr
));
1140 static int dispatch_raw_connection_event(sd_event_source
*event
,
1144 RemoteServer
*s
= userdata
;
1146 SocketAddress addr
= {
1147 .size
= sizeof(union sockaddr_union
),
1148 .type
= SOCK_STREAM
,
1150 char *hostname
= NULL
;
1152 fd2
= accept_connection("raw", fd
, &addr
, &hostname
);
1156 return add_source(s
, fd2
, hostname
, true);
1159 /**********************************************************************
1160 **********************************************************************
1161 **********************************************************************/
1163 static const char* const journal_write_split_mode_table
[_JOURNAL_WRITE_SPLIT_MAX
] = {
1164 [JOURNAL_WRITE_SPLIT_NONE
] = "none",
1165 [JOURNAL_WRITE_SPLIT_HOST
] = "host",
1168 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode
, JournalWriteSplitMode
);
1169 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode
,
1170 journal_write_split_mode
,
1171 JournalWriteSplitMode
,
1172 "Failed to parse split mode setting");
1174 static int parse_config(void) {
1175 const ConfigTableItem items
[] = {
1176 { "Remote", "SplitMode", config_parse_write_split_mode
, 0, &arg_split_mode
},
1177 { "Remote", "ServerKeyFile", config_parse_path
, 0, &arg_key
},
1178 { "Remote", "ServerCertificateFile", config_parse_path
, 0, &arg_cert
},
1179 { "Remote", "TrustedCertificateFile", config_parse_path
, 0, &arg_trust
},
1182 return config_parse_many(PKGSYSCONFDIR
"/journal-remote.conf",
1183 CONF_DIRS_NULSTR("systemd/journal-remote.conf"),
1184 "Remote\0", config_item_table_lookup
, items
,
1188 static void help(void) {
1189 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1190 "Write external journal events to journal file(s).\n\n"
1191 " -h --help Show this help\n"
1192 " --version Show package version\n"
1193 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1194 " --getter=COMMAND Read events from the output of COMMAND\n"
1195 " --listen-raw=ADDR Listen for connections at ADDR\n"
1196 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1197 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1198 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1199 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1200 " --seal[=BOOL] Use event sealing (default: no)\n"
1201 " --key=FILENAME SSL key in PEM format (default:\n"
1202 " \"" PRIV_KEY_FILE
"\")\n"
1203 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1204 " \"" CERT_FILE
"\")\n"
1205 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1206 " \"" TRUST_FILE
"\")\n"
1207 " --gnutls-log=CATEGORY...\n"
1208 " Specify a list of gnutls logging categories\n"
1209 " --split-mode=none|host How many output files to create\n"
1211 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1212 , program_invocation_short_name
);
1215 static int parse_argv(int argc
, char *argv
[]) {
1217 ARG_VERSION
= 0x100,
1232 static const struct option options
[] = {
1233 { "help", no_argument
, NULL
, 'h' },
1234 { "version", no_argument
, NULL
, ARG_VERSION
},
1235 { "url", required_argument
, NULL
, ARG_URL
},
1236 { "getter", required_argument
, NULL
, ARG_GETTER
},
1237 { "listen-raw", required_argument
, NULL
, ARG_LISTEN_RAW
},
1238 { "listen-http", required_argument
, NULL
, ARG_LISTEN_HTTP
},
1239 { "listen-https", required_argument
, NULL
, ARG_LISTEN_HTTPS
},
1240 { "output", required_argument
, NULL
, 'o' },
1241 { "split-mode", required_argument
, NULL
, ARG_SPLIT_MODE
},
1242 { "compress", optional_argument
, NULL
, ARG_COMPRESS
},
1243 { "seal", optional_argument
, NULL
, ARG_SEAL
},
1244 { "key", required_argument
, NULL
, ARG_KEY
},
1245 { "cert", required_argument
, NULL
, ARG_CERT
},
1246 { "trust", required_argument
, NULL
, ARG_TRUST
},
1247 { "gnutls-log", required_argument
, NULL
, ARG_GNUTLS_LOG
},
1252 bool type_a
, type_b
;
1257 while ((c
= getopt_long(argc
, argv
, "ho:", options
, NULL
)) >= 0)
1261 return 0 /* done */;
1268 log_error("cannot currently set more than one --url");
1277 log_error("cannot currently use --getter more than once");
1281 arg_getter
= optarg
;
1284 case ARG_LISTEN_RAW
:
1285 if (arg_listen_raw
) {
1286 log_error("cannot currently use --listen-raw more than once");
1290 arg_listen_raw
= optarg
;
1293 case ARG_LISTEN_HTTP
:
1294 if (arg_listen_http
|| http_socket
>= 0) {
1295 log_error("cannot currently use --listen-http more than once");
1299 r
= negative_fd(optarg
);
1303 arg_listen_http
= optarg
;
1306 case ARG_LISTEN_HTTPS
:
1307 if (arg_listen_https
|| https_socket
>= 0) {
1308 log_error("cannot currently use --listen-https more than once");
1312 r
= negative_fd(optarg
);
1316 arg_listen_https
= optarg
;
1322 log_error("Key file specified twice");
1326 arg_key
= strdup(optarg
);
1334 log_error("Certificate file specified twice");
1338 arg_cert
= strdup(optarg
);
1345 if (arg_trust
|| arg_trust_all
) {
1346 log_error("Confusing trusted CA configuration");
1350 if (streq(optarg
, "all"))
1351 arg_trust_all
= true;
1354 arg_trust
= strdup(optarg
);
1358 log_error("Option --trust is not available.");
1367 log_error("cannot use --output/-o more than once");
1371 arg_output
= optarg
;
1374 case ARG_SPLIT_MODE
:
1375 arg_split_mode
= journal_write_split_mode_from_string(optarg
);
1376 if (arg_split_mode
== _JOURNAL_WRITE_SPLIT_INVALID
) {
1377 log_error("Invalid split mode: %s", optarg
);
1384 r
= parse_boolean(optarg
);
1386 log_error("Failed to parse --compress= parameter.");
1392 arg_compress
= true;
1398 r
= parse_boolean(optarg
);
1400 log_error("Failed to parse --seal= parameter.");
1410 case ARG_GNUTLS_LOG
: {
1412 const char *word
, *state
;
1415 FOREACH_WORD_SEPARATOR(word
, size
, optarg
, ",", state
) {
1418 cat
= strndup(word
, size
);
1422 if (strv_consume(&arg_gnutls_log
, cat
) < 0)
1427 log_error("Option --gnutls-log is not available.");
1436 assert_not_reached("Unknown option code.");
1440 arg_files
= argv
+ optind
;
1442 type_a
= arg_getter
|| !strv_isempty(arg_files
);
1445 || arg_listen_http
|| arg_listen_https
1446 || sd_listen_fds(false) > 0;
1447 if (type_a
&& type_b
) {
1448 log_error("Cannot use file input or --getter with "
1449 "--arg-listen-... or socket activation.");
1454 log_error("Option --output must be specified with file input or --getter.");
1458 arg_split_mode
= JOURNAL_WRITE_SPLIT_NONE
;
1461 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
1462 && arg_output
&& is_dir(arg_output
, true) > 0) {
1463 log_error("For SplitMode=none, output must be a file.");
1467 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
1468 && arg_output
&& is_dir(arg_output
, true) <= 0) {
1469 log_error("For SplitMode=host, output must be a directory.");
1473 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1474 journal_write_split_mode_to_string(arg_split_mode
),
1479 return 1 /* work to do */;
1482 static int load_certificates(char **key
, char **cert
, char **trust
) {
1485 r
= read_full_file(arg_key
?: PRIV_KEY_FILE
, key
, NULL
);
1487 return log_error_errno(r
, "Failed to read key from file '%s': %m",
1488 arg_key
?: PRIV_KEY_FILE
);
1490 r
= read_full_file(arg_cert
?: CERT_FILE
, cert
, NULL
);
1492 return log_error_errno(r
, "Failed to read certificate from file '%s': %m",
1493 arg_cert
?: CERT_FILE
);
1496 log_info("Certificate checking disabled.");
1498 r
= read_full_file(arg_trust
?: TRUST_FILE
, trust
, NULL
);
1500 return log_error_errno(r
, "Failed to read CA certificate file '%s': %m",
1501 arg_trust
?: TRUST_FILE
);
1507 int main(int argc
, char **argv
) {
1508 RemoteServer s
= {};
1510 _cleanup_free_
char *key
= NULL
, *cert
= NULL
, *trust
= NULL
;
1512 log_show_color(true);
1513 log_parse_environment();
1517 return EXIT_FAILURE
;
1519 r
= parse_argv(argc
, argv
);
1521 return r
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;
1524 if (arg_listen_http
|| arg_listen_https
) {
1525 r
= setup_gnutls_logger(arg_gnutls_log
);
1527 return EXIT_FAILURE
;
1530 if (arg_listen_https
|| https_socket
>= 0)
1531 if (load_certificates(&key
, &cert
, &trust
) < 0)
1532 return EXIT_FAILURE
;
1534 if (remoteserver_init(&s
, key
, cert
, trust
) < 0)
1535 return EXIT_FAILURE
;
1537 r
= sd_event_set_watchdog(s
.events
, true);
1539 log_error_errno(r
, "Failed to enable watchdog: %m");
1541 log_debug("Watchdog is %s.", r
> 0 ? "enabled" : "disabled");
1543 log_debug("%s running as pid "PID_FMT
,
1544 program_invocation_short_name
, getpid());
1547 "STATUS=Processing requests...");
1550 r
= sd_event_get_state(s
.events
);
1553 if (r
== SD_EVENT_FINISHED
)
1556 r
= sd_event_run(s
.events
, -1);
1558 log_error_errno(r
, "Failed to run event loop: %m");
1565 "STATUS=Shutting down after writing %" PRIu64
" entries...", s
.event_count
);
1566 log_info("Finishing after writing %" PRIu64
" entries", s
.event_count
);
1574 return r
>= 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;