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 "alloc-util.h"
39 #include "conf-parser.h"
44 #include "journal-file.h"
45 #include "journal-remote-write.h"
46 #include "journal-remote.h"
47 #include "journald-native.h"
49 #include "parse-util.h"
50 #include "signal-util.h"
51 #include "socket-util.h"
52 #include "stat-util.h"
53 #include "stdio-util.h"
54 #include "string-table.h"
55 #include "string-util.h"
58 #define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
60 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
61 #define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
62 #define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
64 static char* arg_url
= NULL
;
65 static char* arg_getter
= NULL
;
66 static char* arg_listen_raw
= NULL
;
67 static char* arg_listen_http
= NULL
;
68 static char* arg_listen_https
= NULL
;
69 static char** arg_files
= NULL
;
70 static int arg_compress
= true;
71 static int arg_seal
= false;
72 static int http_socket
= -1, https_socket
= -1;
73 static char** arg_gnutls_log
= NULL
;
75 static JournalWriteSplitMode arg_split_mode
= JOURNAL_WRITE_SPLIT_HOST
;
76 static char* arg_output
= NULL
;
78 static char *arg_key
= NULL
;
79 static char *arg_cert
= NULL
;
80 static char *arg_trust
= NULL
;
81 static bool arg_trust_all
= false;
83 /**********************************************************************
84 **********************************************************************
85 **********************************************************************/
87 static int spawn_child(const char* child
, char** argv
) {
89 pid_t parent_pid
, child_pid
;
93 return log_error_errno(errno
, "Failed to create pager pipe: %m");
95 parent_pid
= getpid();
99 r
= log_error_errno(errno
, "Failed to fork: %m");
105 if (child_pid
== 0) {
107 (void) reset_all_signal_handlers();
108 (void) reset_signal_mask();
110 r
= dup2(fd
[1], STDOUT_FILENO
);
112 log_error_errno(errno
, "Failed to dup pipe to stdout: %m");
118 /* Make sure the child goes away when the parent dies */
119 if (prctl(PR_SET_PDEATHSIG
, SIGTERM
) < 0)
122 /* Check whether our parent died before we were able
123 * to set the death signal */
124 if (getppid() != parent_pid
)
128 log_error_errno(errno
, "Failed to exec child %s: %m", child
);
134 log_warning_errno(errno
, "Failed to close write end of pipe: %m");
139 static int spawn_curl(const char* url
) {
140 char **argv
= STRV_MAKE("curl",
141 "-HAccept: application/vnd.fdo.journal",
147 r
= spawn_child("curl", argv
);
149 log_error_errno(r
, "Failed to spawn curl: %m");
153 static int spawn_getter(const char *getter
, const char *url
) {
155 _cleanup_strv_free_
char **words
= NULL
;
158 r
= strv_split_extract(&words
, getter
, WHITESPACE
, EXTRACT_QUOTES
);
160 return log_error_errno(r
, "Failed to split getter option: %m");
162 r
= strv_extend(&words
, url
);
164 return log_error_errno(r
, "Failed to create command line: %m");
166 r
= spawn_child(words
[0], words
);
168 log_error_errno(r
, "Failed to spawn getter %s: %m", getter
);
173 #define filename_escape(s) xescape((s), "/ ")
175 static int open_output(Writer
*w
, const char* host
) {
176 _cleanup_free_
char *_output
= NULL
;
180 switch (arg_split_mode
) {
181 case JOURNAL_WRITE_SPLIT_NONE
:
182 output
= arg_output
?: REMOTE_JOURNAL_PATH
"/remote.journal";
185 case JOURNAL_WRITE_SPLIT_HOST
: {
186 _cleanup_free_
char *name
;
190 name
= filename_escape(host
);
194 r
= asprintf(&_output
, "%s/remote-%s.journal",
195 arg_output
?: REMOTE_JOURNAL_PATH
,
205 assert_not_reached("what?");
208 r
= journal_file_open_reliably(output
,
209 O_RDWR
|O_CREAT
, 0640,
210 arg_compress
, arg_seal
,
215 log_error_errno(r
, "Failed to open output journal %s: %m",
218 log_debug("Opened output file %s", w
->journal
->path
);
222 /**********************************************************************
223 **********************************************************************
224 **********************************************************************/
226 static int init_writer_hashmap(RemoteServer
*s
) {
227 static const struct hash_ops
*hash_ops
[] = {
228 [JOURNAL_WRITE_SPLIT_NONE
] = NULL
,
229 [JOURNAL_WRITE_SPLIT_HOST
] = &string_hash_ops
,
232 assert(arg_split_mode
>= 0 && arg_split_mode
< (int) ELEMENTSOF(hash_ops
));
234 s
->writers
= hashmap_new(hash_ops
[arg_split_mode
]);
241 static int get_writer(RemoteServer
*s
, const char *host
,
244 _cleanup_writer_unref_ Writer
*w
= NULL
;
247 switch(arg_split_mode
) {
248 case JOURNAL_WRITE_SPLIT_NONE
:
249 key
= "one and only";
252 case JOURNAL_WRITE_SPLIT_HOST
:
258 assert_not_reached("what split mode?");
261 w
= hashmap_get(s
->writers
, key
);
269 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
) {
270 w
->hashmap_key
= strdup(key
);
275 r
= open_output(w
, host
);
279 r
= hashmap_put(s
->writers
, w
->hashmap_key
?: key
, w
);
289 /**********************************************************************
290 **********************************************************************
291 **********************************************************************/
293 /* This should go away as soon as µhttpd allows state to be passed around. */
294 static RemoteServer
*server
;
296 static int dispatch_raw_source_event(sd_event_source
*event
,
300 static int dispatch_raw_source_until_block(sd_event_source
*event
,
302 static int dispatch_blocking_source_event(sd_event_source
*event
,
304 static int dispatch_raw_connection_event(sd_event_source
*event
,
308 static int dispatch_http_event(sd_event_source
*event
,
313 static int get_source_for_fd(RemoteServer
*s
,
314 int fd
, char *name
, RemoteSource
**source
) {
318 /* This takes ownership of name, but only on success. */
323 if (!GREEDY_REALLOC0(s
->sources
, s
->sources_size
, fd
+ 1))
326 r
= get_writer(s
, name
, &writer
);
328 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
331 if (s
->sources
[fd
] == NULL
) {
332 s
->sources
[fd
] = source_new(fd
, false, name
, writer
);
333 if (!s
->sources
[fd
]) {
334 writer_unref(writer
);
341 *source
= s
->sources
[fd
];
345 static int remove_source(RemoteServer
*s
, int fd
) {
346 RemoteSource
*source
;
349 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
351 source
= s
->sources
[fd
];
353 /* this closes fd too */
355 s
->sources
[fd
] = NULL
;
362 static int add_source(RemoteServer
*s
, int fd
, char* name
, bool own_name
) {
364 RemoteSource
*source
= NULL
;
367 /* This takes ownership of name, even on failure, if own_name is true. */
379 r
= get_source_for_fd(s
, fd
, name
, &source
);
381 log_error_errno(r
, "Failed to create source for fd:%d (%s): %m",
387 r
= sd_event_add_io(s
->events
, &source
->event
,
388 fd
, EPOLLIN
|EPOLLRDHUP
|EPOLLPRI
,
389 dispatch_raw_source_event
, source
);
391 /* Add additional source for buffer processing. It will be
393 r
= sd_event_add_defer(s
->events
, &source
->buffer_event
,
394 dispatch_raw_source_until_block
, source
);
396 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_OFF
);
397 } else if (r
== -EPERM
) {
398 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd
, name
);
399 r
= sd_event_add_defer(s
->events
, &source
->event
,
400 dispatch_blocking_source_event
, source
);
402 sd_event_source_set_enabled(source
->event
, SD_EVENT_ON
);
405 log_error_errno(r
, "Failed to register event source for fd:%d: %m",
410 r
= sd_event_source_set_description(source
->event
, name
);
412 log_error_errno(r
, "Failed to set source name for fd:%d: %m", fd
);
416 return 1; /* work to do */
419 remove_source(s
, fd
);
423 static int add_raw_socket(RemoteServer
*s
, int fd
) {
425 _cleanup_close_
int fd_
= fd
;
426 char name
[sizeof("raw-socket-")-1 + DECIMAL_STR_MAX(int) + 1];
430 r
= sd_event_add_io(s
->events
, &s
->listen_event
,
432 dispatch_raw_connection_event
, s
);
436 xsprintf(name
, "raw-socket-%d", fd
);
438 r
= sd_event_source_set_description(s
->listen_event
, name
);
447 static int setup_raw_socket(RemoteServer
*s
, const char *address
) {
450 fd
= make_socket_fd(LOG_INFO
, address
, SOCK_STREAM
| SOCK_CLOEXEC
);
454 return add_raw_socket(s
, fd
);
457 /**********************************************************************
458 **********************************************************************
459 **********************************************************************/
461 static int request_meta(void **connection_cls
, int fd
, char *hostname
) {
462 RemoteSource
*source
;
466 assert(connection_cls
);
470 r
= get_writer(server
, hostname
, &writer
);
472 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
475 source
= source_new(fd
, true, hostname
, writer
);
477 writer_unref(writer
);
481 log_debug("Added RemoteSource as connection metadata %p", source
);
483 *connection_cls
= source
;
487 static void request_meta_free(void *cls
,
488 struct MHD_Connection
*connection
,
489 void **connection_cls
,
490 enum MHD_RequestTerminationCode toe
) {
493 assert(connection_cls
);
497 log_debug("Cleaning up connection metadata %p", s
);
499 *connection_cls
= NULL
;
503 static int process_http_upload(
504 struct MHD_Connection
*connection
,
505 const char *upload_data
,
506 size_t *upload_data_size
,
507 RemoteSource
*source
) {
509 bool finished
= false;
515 log_trace("%s: connection %p, %zu bytes",
516 __func__
, connection
, *upload_data_size
);
518 if (*upload_data_size
) {
519 log_trace("Received %zu bytes", *upload_data_size
);
521 r
= push_data(source
, upload_data
, *upload_data_size
);
523 return mhd_respond_oom(connection
);
525 *upload_data_size
= 0;
530 r
= process_source(source
, arg_compress
, arg_seal
);
534 log_warning("Failed to process data for connection %p", connection
);
536 return mhd_respondf(connection
,
537 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
,
538 "Entry is too large, maximum is %u bytes.\n",
541 return mhd_respondf(connection
,
542 MHD_HTTP_UNPROCESSABLE_ENTITY
,
543 "Processing failed: %s.", strerror(-r
));
550 /* The upload is finished */
552 remaining
= source_non_empty(source
);
554 log_warning("Premature EOFbyte. %zu bytes lost.", remaining
);
555 return mhd_respondf(connection
, MHD_HTTP_EXPECTATION_FAILED
,
556 "Premature EOF. %zu bytes of trailing data not processed.",
560 return mhd_respond(connection
, MHD_HTTP_ACCEPTED
, "OK.\n");
563 static int request_handler(
565 struct MHD_Connection
*connection
,
569 const char *upload_data
,
570 size_t *upload_data_size
,
571 void **connection_cls
) {
575 _cleanup_free_
char *hostname
= NULL
;
578 assert(connection_cls
);
582 log_trace("Handling a connection %s %s %s", method
, url
, version
);
585 return process_http_upload(connection
,
586 upload_data
, upload_data_size
,
589 if (!streq(method
, "POST"))
590 return mhd_respond(connection
, MHD_HTTP_METHOD_NOT_ACCEPTABLE
,
591 "Unsupported method.\n");
593 if (!streq(url
, "/upload"))
594 return mhd_respond(connection
, MHD_HTTP_NOT_FOUND
,
597 header
= MHD_lookup_connection_value(connection
,
598 MHD_HEADER_KIND
, "Content-Type");
599 if (!header
|| !streq(header
, "application/vnd.fdo.journal"))
600 return mhd_respond(connection
, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE
,
601 "Content-Type: application/vnd.fdo.journal"
605 const union MHD_ConnectionInfo
*ci
;
607 ci
= MHD_get_connection_info(connection
,
608 MHD_CONNECTION_INFO_CONNECTION_FD
);
610 log_error("MHD_get_connection_info failed: cannot get remote fd");
611 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
612 "Cannot check remote address");
619 if (server
->check_trust
) {
620 r
= check_permissions(connection
, &code
, &hostname
);
624 r
= getnameinfo_pretty(fd
, &hostname
);
626 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
627 "Cannot check remote hostname");
632 r
= request_meta(connection_cls
, fd
, hostname
);
634 return respond_oom(connection
);
636 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
643 static int setup_microhttpd_server(RemoteServer
*s
,
648 struct MHD_OptionItem opts
[] = {
649 { MHD_OPTION_NOTIFY_COMPLETED
, (intptr_t) request_meta_free
},
650 { MHD_OPTION_EXTERNAL_LOGGER
, (intptr_t) microhttpd_logger
},
651 { MHD_OPTION_LISTEN_SOCKET
, fd
},
652 { MHD_OPTION_CONNECTION_MEMORY_LIMIT
, DATA_SIZE_MAX
},
661 MHD_USE_EPOLL_LINUX_ONLY
|
662 MHD_USE_PEDANTIC_CHECKS
|
663 MHD_USE_PIPE_FOR_SHUTDOWN
;
665 const union MHD_DaemonInfo
*info
;
671 r
= fd_nonblock(fd
, true);
673 return log_error_errno(r
, "Failed to make fd:%d nonblocking: %m", fd
);
678 opts
[opts_pos
++] = (struct MHD_OptionItem
)
679 {MHD_OPTION_HTTPS_MEM_KEY
, 0, (char*) key
};
680 opts
[opts_pos
++] = (struct MHD_OptionItem
)
681 {MHD_OPTION_HTTPS_MEM_CERT
, 0, (char*) cert
};
683 flags
|= MHD_USE_SSL
;
686 opts
[opts_pos
++] = (struct MHD_OptionItem
)
687 {MHD_OPTION_HTTPS_MEM_TRUST
, 0, (char*) trust
};
690 d
= new(MHDDaemonWrapper
, 1);
694 d
->fd
= (uint64_t) fd
;
696 d
->daemon
= MHD_start_daemon(flags
, 0,
698 request_handler
, NULL
,
699 MHD_OPTION_ARRAY
, opts
,
702 log_error("Failed to start µhttp daemon");
707 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
708 key
? "HTTPS" : "HTTP", fd
, d
);
711 info
= MHD_get_daemon_info(d
->daemon
, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY
);
713 log_error("µhttp returned NULL daemon info");
718 epoll_fd
= info
->listen_fd
;
720 log_error("µhttp epoll fd is invalid");
725 r
= sd_event_add_io(s
->events
, &d
->event
,
727 dispatch_http_event
, d
);
729 log_error_errno(r
, "Failed to add event callback: %m");
733 r
= sd_event_source_set_description(d
->event
, "epoll-fd");
735 log_error_errno(r
, "Failed to set source name: %m");
739 r
= hashmap_ensure_allocated(&s
->daemons
, &uint64_hash_ops
);
745 r
= hashmap_put(s
->daemons
, &d
->fd
, d
);
747 log_error_errno(r
, "Failed to add daemon to hashmap: %m");
755 MHD_stop_daemon(d
->daemon
);
761 static int setup_microhttpd_socket(RemoteServer
*s
,
768 fd
= make_socket_fd(LOG_DEBUG
, address
, SOCK_STREAM
| SOCK_CLOEXEC
);
772 return setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
775 static int dispatch_http_event(sd_event_source
*event
,
779 MHDDaemonWrapper
*d
= userdata
;
784 r
= MHD_run(d
->daemon
);
786 log_error("MHD_run failed!");
787 // XXX: unregister daemon
791 return 1; /* work to do */
794 /**********************************************************************
795 **********************************************************************
796 **********************************************************************/
798 static int setup_signals(RemoteServer
*s
) {
803 assert_se(sigprocmask_many(SIG_SETMASK
, NULL
, SIGINT
, SIGTERM
, -1) >= 0);
805 r
= sd_event_add_signal(s
->events
, &s
->sigterm_event
, SIGTERM
, NULL
, s
);
809 r
= sd_event_add_signal(s
->events
, &s
->sigint_event
, SIGINT
, NULL
, s
);
816 static int negative_fd(const char *spec
) {
817 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
821 r
= safe_atoi(spec
, &fd
);
831 static int remoteserver_init(RemoteServer
*s
,
840 if ((arg_listen_raw
|| arg_listen_http
) && trust
) {
841 log_error("Option --trust makes all non-HTTPS connections untrusted.");
845 r
= sd_event_default(&s
->events
);
847 return log_error_errno(r
, "Failed to allocate event loop: %m");
851 assert(server
== NULL
);
854 r
= init_writer_hashmap(s
);
858 n
= sd_listen_fds(true);
860 return log_error_errno(n
, "Failed to read listening file descriptors from environment: %m");
862 log_debug("Received %d descriptors", n
);
864 if (MAX(http_socket
, https_socket
) >= SD_LISTEN_FDS_START
+ n
) {
865 log_error("Received fewer sockets than expected");
869 for (fd
= SD_LISTEN_FDS_START
; fd
< SD_LISTEN_FDS_START
+ n
; fd
++) {
870 if (sd_is_socket(fd
, AF_UNSPEC
, 0, true)) {
871 log_debug("Received a listening socket (fd:%d)", fd
);
873 if (fd
== http_socket
)
874 r
= setup_microhttpd_server(s
, fd
, NULL
, NULL
, NULL
);
875 else if (fd
== https_socket
)
876 r
= setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
878 r
= add_raw_socket(s
, fd
);
879 } else if (sd_is_socket(fd
, AF_UNSPEC
, 0, false)) {
882 r
= getnameinfo_pretty(fd
, &hostname
);
884 return log_error_errno(r
, "Failed to retrieve remote name: %m");
886 log_debug("Received a connection socket (fd:%d) from %s", fd
, hostname
);
888 r
= add_source(s
, fd
, hostname
, true);
890 log_error("Unknown socket passed on fd:%d", fd
);
896 return log_error_errno(r
, "Failed to register socket (fd:%d): %m",
901 const char *url
, *hostname
;
903 url
= strjoina(arg_url
, "/entries");
906 log_info("Spawning getter %s...", url
);
907 fd
= spawn_getter(arg_getter
, url
);
909 log_info("Spawning curl %s...", url
);
910 fd
= spawn_curl(url
);
916 startswith(arg_url
, "https://") ?:
917 startswith(arg_url
, "http://") ?:
920 r
= add_source(s
, fd
, (char*) hostname
, false);
925 if (arg_listen_raw
) {
926 log_debug("Listening on a socket...");
927 r
= setup_raw_socket(s
, arg_listen_raw
);
932 if (arg_listen_http
) {
933 r
= setup_microhttpd_socket(s
, arg_listen_http
, NULL
, NULL
, NULL
);
938 if (arg_listen_https
) {
939 r
= setup_microhttpd_socket(s
, arg_listen_https
, key
, cert
, trust
);
944 STRV_FOREACH(file
, arg_files
) {
945 const char *output_name
;
947 if (streq(*file
, "-")) {
948 log_debug("Using standard input as source.");
951 output_name
= "stdin";
953 log_debug("Reading file %s...", *file
);
955 fd
= open(*file
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
957 return log_error_errno(errno
, "Failed to open %s: %m", *file
);
961 r
= add_source(s
, fd
, (char*) output_name
, false);
966 if (s
->active
== 0) {
967 log_error("Zero sources specified");
971 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
) {
972 /* In this case we know what the writer will be
973 called, so we can create it and verify that we can
974 create output as expected. */
975 r
= get_writer(s
, NULL
, &s
->_single_writer
);
983 static void server_destroy(RemoteServer
*s
) {
987 while ((d
= hashmap_steal_first(s
->daemons
))) {
988 MHD_stop_daemon(d
->daemon
);
989 sd_event_source_unref(d
->event
);
993 hashmap_free(s
->daemons
);
995 assert(s
->sources_size
== 0 || s
->sources
);
996 for (i
= 0; i
< s
->sources_size
; i
++)
1000 writer_unref(s
->_single_writer
);
1001 hashmap_free(s
->writers
);
1003 sd_event_source_unref(s
->sigterm_event
);
1004 sd_event_source_unref(s
->sigint_event
);
1005 sd_event_source_unref(s
->listen_event
);
1006 sd_event_unref(s
->events
);
1008 /* fds that we're listening on remain open... */
1011 /**********************************************************************
1012 **********************************************************************
1013 **********************************************************************/
1015 static int handle_raw_source(sd_event_source
*event
,
1020 RemoteSource
*source
;
1023 /* Returns 1 if there might be more data pending,
1024 * 0 if data is currently exhausted, negative on error.
1027 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
1028 source
= s
->sources
[fd
];
1029 assert(source
->fd
== fd
);
1031 r
= process_source(source
, arg_compress
, arg_seal
);
1032 if (source
->state
== STATE_EOF
) {
1035 log_debug("EOF reached with source fd:%d (%s)",
1036 source
->fd
, source
->name
);
1038 remaining
= source_non_empty(source
);
1040 log_notice("Premature EOF. %zu bytes lost.", remaining
);
1041 remove_source(s
, source
->fd
);
1042 log_debug("%zu active sources remaining", s
->active
);
1044 } else if (r
== -E2BIG
) {
1045 log_notice_errno(E2BIG
, "Entry too big, skipped");
1047 } else if (r
== -EAGAIN
) {
1050 log_debug_errno(r
, "Closing connection: %m");
1051 remove_source(server
, fd
);
1057 static int dispatch_raw_source_until_block(sd_event_source
*event
,
1059 RemoteSource
*source
= userdata
;
1062 /* Make sure event stays around even if source is destroyed */
1063 sd_event_source_ref(event
);
1065 r
= handle_raw_source(event
, source
->fd
, EPOLLIN
, server
);
1067 /* No more data for now */
1068 sd_event_source_set_enabled(event
, SD_EVENT_OFF
);
1070 sd_event_source_unref(event
);
1075 static int dispatch_raw_source_event(sd_event_source
*event
,
1079 RemoteSource
*source
= userdata
;
1082 assert(source
->event
);
1083 assert(source
->buffer_event
);
1085 r
= handle_raw_source(event
, fd
, EPOLLIN
, server
);
1087 /* Might have more data. We need to rerun the handler
1088 * until we are sure the buffer is exhausted. */
1089 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_ON
);
1094 static int dispatch_blocking_source_event(sd_event_source
*event
,
1096 RemoteSource
*source
= userdata
;
1098 return handle_raw_source(event
, source
->fd
, EPOLLIN
, server
);
1101 static int accept_connection(const char* type
, int fd
,
1102 SocketAddress
*addr
, char **hostname
) {
1105 log_debug("Accepting new %s connection on fd:%d", type
, fd
);
1106 fd2
= accept4(fd
, &addr
->sockaddr
.sa
, &addr
->size
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
1108 return log_error_errno(errno
, "accept() on fd:%d failed: %m", fd
);
1110 switch(socket_address_family(addr
)) {
1113 _cleanup_free_
char *a
= NULL
;
1116 r
= socket_address_print(addr
, &a
);
1118 log_error_errno(r
, "socket_address_print(): %m");
1123 r
= socknameinfo_pretty(&addr
->sockaddr
, addr
->size
, &b
);
1125 log_error_errno(r
, "Resolving hostname failed: %m");
1130 log_debug("Accepted %s %s connection from %s",
1132 socket_address_family(addr
) == AF_INET
? "IP" : "IPv6",
1140 log_error("Rejected %s connection with unsupported family %d",
1141 type
, socket_address_family(addr
));
1148 static int dispatch_raw_connection_event(sd_event_source
*event
,
1152 RemoteServer
*s
= userdata
;
1154 SocketAddress addr
= {
1155 .size
= sizeof(union sockaddr_union
),
1156 .type
= SOCK_STREAM
,
1158 char *hostname
= NULL
;
1160 fd2
= accept_connection("raw", fd
, &addr
, &hostname
);
1164 return add_source(s
, fd2
, hostname
, true);
1167 /**********************************************************************
1168 **********************************************************************
1169 **********************************************************************/
1171 static const char* const journal_write_split_mode_table
[_JOURNAL_WRITE_SPLIT_MAX
] = {
1172 [JOURNAL_WRITE_SPLIT_NONE
] = "none",
1173 [JOURNAL_WRITE_SPLIT_HOST
] = "host",
1176 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode
, JournalWriteSplitMode
);
1177 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode
,
1178 journal_write_split_mode
,
1179 JournalWriteSplitMode
,
1180 "Failed to parse split mode setting");
1182 static int parse_config(void) {
1183 const ConfigTableItem items
[] = {
1184 { "Remote", "Seal", config_parse_bool
, 0, &arg_seal
},
1185 { "Remote", "SplitMode", config_parse_write_split_mode
, 0, &arg_split_mode
},
1186 { "Remote", "ServerKeyFile", config_parse_path
, 0, &arg_key
},
1187 { "Remote", "ServerCertificateFile", config_parse_path
, 0, &arg_cert
},
1188 { "Remote", "TrustedCertificateFile", config_parse_path
, 0, &arg_trust
},
1191 return config_parse_many(PKGSYSCONFDIR
"/journal-remote.conf",
1192 CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"),
1193 "Remote\0", config_item_table_lookup
, items
,
1197 static void help(void) {
1198 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1199 "Write external journal events to journal file(s).\n\n"
1200 " -h --help Show this help\n"
1201 " --version Show package version\n"
1202 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1203 " --getter=COMMAND Read events from the output of COMMAND\n"
1204 " --listen-raw=ADDR Listen for connections at ADDR\n"
1205 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1206 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1207 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1208 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1209 " --seal[=BOOL] Use event sealing (default: no)\n"
1210 " --key=FILENAME SSL key in PEM format (default:\n"
1211 " \"" PRIV_KEY_FILE
"\")\n"
1212 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1213 " \"" CERT_FILE
"\")\n"
1214 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1215 " \"" TRUST_FILE
"\")\n"
1216 " --gnutls-log=CATEGORY...\n"
1217 " Specify a list of gnutls logging categories\n"
1218 " --split-mode=none|host How many output files to create\n"
1220 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1221 , program_invocation_short_name
);
1224 static int parse_argv(int argc
, char *argv
[]) {
1226 ARG_VERSION
= 0x100,
1241 static const struct option options
[] = {
1242 { "help", no_argument
, NULL
, 'h' },
1243 { "version", no_argument
, NULL
, ARG_VERSION
},
1244 { "url", required_argument
, NULL
, ARG_URL
},
1245 { "getter", required_argument
, NULL
, ARG_GETTER
},
1246 { "listen-raw", required_argument
, NULL
, ARG_LISTEN_RAW
},
1247 { "listen-http", required_argument
, NULL
, ARG_LISTEN_HTTP
},
1248 { "listen-https", required_argument
, NULL
, ARG_LISTEN_HTTPS
},
1249 { "output", required_argument
, NULL
, 'o' },
1250 { "split-mode", required_argument
, NULL
, ARG_SPLIT_MODE
},
1251 { "compress", optional_argument
, NULL
, ARG_COMPRESS
},
1252 { "seal", optional_argument
, NULL
, ARG_SEAL
},
1253 { "key", required_argument
, NULL
, ARG_KEY
},
1254 { "cert", required_argument
, NULL
, ARG_CERT
},
1255 { "trust", required_argument
, NULL
, ARG_TRUST
},
1256 { "gnutls-log", required_argument
, NULL
, ARG_GNUTLS_LOG
},
1261 bool type_a
, type_b
;
1266 while ((c
= getopt_long(argc
, argv
, "ho:", options
, NULL
)) >= 0)
1270 return 0 /* done */;
1277 log_error("cannot currently set more than one --url");
1286 log_error("cannot currently use --getter more than once");
1290 arg_getter
= optarg
;
1293 case ARG_LISTEN_RAW
:
1294 if (arg_listen_raw
) {
1295 log_error("cannot currently use --listen-raw more than once");
1299 arg_listen_raw
= optarg
;
1302 case ARG_LISTEN_HTTP
:
1303 if (arg_listen_http
|| http_socket
>= 0) {
1304 log_error("cannot currently use --listen-http more than once");
1308 r
= negative_fd(optarg
);
1312 arg_listen_http
= optarg
;
1315 case ARG_LISTEN_HTTPS
:
1316 if (arg_listen_https
|| https_socket
>= 0) {
1317 log_error("cannot currently use --listen-https more than once");
1321 r
= negative_fd(optarg
);
1325 arg_listen_https
= optarg
;
1331 log_error("Key file specified twice");
1335 arg_key
= strdup(optarg
);
1343 log_error("Certificate file specified twice");
1347 arg_cert
= strdup(optarg
);
1354 if (arg_trust
|| arg_trust_all
) {
1355 log_error("Confusing trusted CA configuration");
1359 if (streq(optarg
, "all"))
1360 arg_trust_all
= true;
1363 arg_trust
= strdup(optarg
);
1367 log_error("Option --trust is not available.");
1376 log_error("cannot use --output/-o more than once");
1380 arg_output
= optarg
;
1383 case ARG_SPLIT_MODE
:
1384 arg_split_mode
= journal_write_split_mode_from_string(optarg
);
1385 if (arg_split_mode
== _JOURNAL_WRITE_SPLIT_INVALID
) {
1386 log_error("Invalid split mode: %s", optarg
);
1393 r
= parse_boolean(optarg
);
1395 log_error("Failed to parse --compress= parameter.");
1401 arg_compress
= true;
1407 r
= parse_boolean(optarg
);
1409 log_error("Failed to parse --seal= parameter.");
1419 case ARG_GNUTLS_LOG
: {
1421 const char* p
= optarg
;
1423 _cleanup_free_
char *word
= NULL
;
1425 r
= extract_first_word(&p
, &word
, ",", 0);
1427 return log_error_errno(r
, "Failed to parse --gnutls-log= argument: %m");
1432 if (strv_push(&arg_gnutls_log
, word
) < 0)
1439 log_error("Option --gnutls-log is not available.");
1448 assert_not_reached("Unknown option code.");
1452 arg_files
= argv
+ optind
;
1454 type_a
= arg_getter
|| !strv_isempty(arg_files
);
1457 || arg_listen_http
|| arg_listen_https
1458 || sd_listen_fds(false) > 0;
1459 if (type_a
&& type_b
) {
1460 log_error("Cannot use file input or --getter with "
1461 "--arg-listen-... or socket activation.");
1466 log_error("Option --output must be specified with file input or --getter.");
1470 arg_split_mode
= JOURNAL_WRITE_SPLIT_NONE
;
1473 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
1474 && arg_output
&& is_dir(arg_output
, true) > 0) {
1475 log_error("For SplitMode=none, output must be a file.");
1479 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
1480 && arg_output
&& is_dir(arg_output
, true) <= 0) {
1481 log_error("For SplitMode=host, output must be a directory.");
1485 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1486 journal_write_split_mode_to_string(arg_split_mode
),
1491 return 1 /* work to do */;
1494 static int load_certificates(char **key
, char **cert
, char **trust
) {
1497 r
= read_full_file(arg_key
?: PRIV_KEY_FILE
, key
, NULL
);
1499 return log_error_errno(r
, "Failed to read key from file '%s': %m",
1500 arg_key
?: PRIV_KEY_FILE
);
1502 r
= read_full_file(arg_cert
?: CERT_FILE
, cert
, NULL
);
1504 return log_error_errno(r
, "Failed to read certificate from file '%s': %m",
1505 arg_cert
?: CERT_FILE
);
1508 log_info("Certificate checking disabled.");
1510 r
= read_full_file(arg_trust
?: TRUST_FILE
, trust
, NULL
);
1512 return log_error_errno(r
, "Failed to read CA certificate file '%s': %m",
1513 arg_trust
?: TRUST_FILE
);
1519 int main(int argc
, char **argv
) {
1520 RemoteServer s
= {};
1522 _cleanup_free_
char *key
= NULL
, *cert
= NULL
, *trust
= NULL
;
1524 log_show_color(true);
1525 log_parse_environment();
1529 return EXIT_FAILURE
;
1531 r
= parse_argv(argc
, argv
);
1533 return r
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;
1536 if (arg_listen_http
|| arg_listen_https
) {
1537 r
= setup_gnutls_logger(arg_gnutls_log
);
1539 return EXIT_FAILURE
;
1542 if (arg_listen_https
|| https_socket
>= 0)
1543 if (load_certificates(&key
, &cert
, &trust
) < 0)
1544 return EXIT_FAILURE
;
1546 if (remoteserver_init(&s
, key
, cert
, trust
) < 0)
1547 return EXIT_FAILURE
;
1549 r
= sd_event_set_watchdog(s
.events
, true);
1551 log_error_errno(r
, "Failed to enable watchdog: %m");
1553 log_debug("Watchdog is %s.", r
> 0 ? "enabled" : "disabled");
1555 log_debug("%s running as pid "PID_FMT
,
1556 program_invocation_short_name
, getpid());
1559 "STATUS=Processing requests...");
1562 r
= sd_event_get_state(s
.events
);
1565 if (r
== SD_EVENT_FINISHED
)
1568 r
= sd_event_run(s
.events
, -1);
1570 log_error_errno(r
, "Failed to run event loop: %m");
1577 "STATUS=Shutting down after writing %" PRIu64
" entries...", s
.event_count
);
1578 log_info("Finishing after writing %" PRIu64
" entries", s
.event_count
);
1586 return r
>= 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;