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"
42 #include "journal-file.h"
43 #include "journal-remote-write.h"
44 #include "journal-remote.h"
45 #include "journald-native.h"
47 #include "signal-util.h"
48 #include "socket-util.h"
49 #include "string-util.h"
52 #define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
54 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
55 #define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
56 #define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
58 static char* arg_url
= NULL
;
59 static char* arg_getter
= NULL
;
60 static char* arg_listen_raw
= NULL
;
61 static char* arg_listen_http
= NULL
;
62 static char* arg_listen_https
= NULL
;
63 static char** arg_files
= NULL
;
64 static int arg_compress
= true;
65 static int arg_seal
= false;
66 static int http_socket
= -1, https_socket
= -1;
67 static char** arg_gnutls_log
= NULL
;
69 static JournalWriteSplitMode arg_split_mode
= JOURNAL_WRITE_SPLIT_HOST
;
70 static char* arg_output
= NULL
;
72 static char *arg_key
= NULL
;
73 static char *arg_cert
= NULL
;
74 static char *arg_trust
= NULL
;
75 static bool arg_trust_all
= false;
77 /**********************************************************************
78 **********************************************************************
79 **********************************************************************/
81 static int spawn_child(const char* child
, char** argv
) {
83 pid_t parent_pid
, child_pid
;
87 return log_error_errno(errno
, "Failed to create pager pipe: %m");
89 parent_pid
= getpid();
93 r
= log_error_errno(errno
, "Failed to fork: %m");
101 (void) reset_all_signal_handlers();
102 (void) reset_signal_mask();
104 r
= dup2(fd
[1], STDOUT_FILENO
);
106 log_error_errno(errno
, "Failed to dup pipe to stdout: %m");
112 /* Make sure the child goes away when the parent dies */
113 if (prctl(PR_SET_PDEATHSIG
, SIGTERM
) < 0)
116 /* Check whether our parent died before we were able
117 * to set the death signal */
118 if (getppid() != parent_pid
)
122 log_error_errno(errno
, "Failed to exec child %s: %m", child
);
128 log_warning_errno(errno
, "Failed to close write end of pipe: %m");
133 static int spawn_curl(const char* url
) {
134 char **argv
= STRV_MAKE("curl",
135 "-HAccept: application/vnd.fdo.journal",
141 r
= spawn_child("curl", argv
);
143 log_error_errno(errno
, "Failed to spawn curl: %m");
147 static int spawn_getter(const char *getter
, const char *url
) {
149 _cleanup_strv_free_
char **words
= NULL
;
152 r
= strv_split_extract(&words
, getter
, WHITESPACE
, EXTRACT_QUOTES
);
154 return log_error_errno(r
, "Failed to split getter option: %m");
156 r
= strv_extend(&words
, url
);
158 return log_error_errno(r
, "Failed to create command line: %m");
160 r
= spawn_child(words
[0], words
);
162 log_error_errno(errno
, "Failed to spawn getter %s: %m", getter
);
167 #define filename_escape(s) xescape((s), "/ ")
169 static int open_output(Writer
*w
, const char* host
) {
170 _cleanup_free_
char *_output
= NULL
;
174 switch (arg_split_mode
) {
175 case JOURNAL_WRITE_SPLIT_NONE
:
176 output
= arg_output
?: REMOTE_JOURNAL_PATH
"/remote.journal";
179 case JOURNAL_WRITE_SPLIT_HOST
: {
180 _cleanup_free_
char *name
;
184 name
= filename_escape(host
);
188 r
= asprintf(&_output
, "%s/remote-%s.journal",
189 arg_output
?: REMOTE_JOURNAL_PATH
,
199 assert_not_reached("what?");
202 r
= journal_file_open_reliably(output
,
203 O_RDWR
|O_CREAT
, 0640,
204 arg_compress
, arg_seal
,
209 log_error_errno(r
, "Failed to open output journal %s: %m",
212 log_debug("Opened output file %s", w
->journal
->path
);
216 /**********************************************************************
217 **********************************************************************
218 **********************************************************************/
220 static int init_writer_hashmap(RemoteServer
*s
) {
221 static const struct hash_ops
*hash_ops
[] = {
222 [JOURNAL_WRITE_SPLIT_NONE
] = NULL
,
223 [JOURNAL_WRITE_SPLIT_HOST
] = &string_hash_ops
,
226 assert(arg_split_mode
>= 0 && arg_split_mode
< (int) ELEMENTSOF(hash_ops
));
228 s
->writers
= hashmap_new(hash_ops
[arg_split_mode
]);
235 static int get_writer(RemoteServer
*s
, const char *host
,
238 _cleanup_writer_unref_ Writer
*w
= NULL
;
241 switch(arg_split_mode
) {
242 case JOURNAL_WRITE_SPLIT_NONE
:
243 key
= "one and only";
246 case JOURNAL_WRITE_SPLIT_HOST
:
252 assert_not_reached("what split mode?");
255 w
= hashmap_get(s
->writers
, key
);
263 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
) {
264 w
->hashmap_key
= strdup(key
);
269 r
= open_output(w
, host
);
273 r
= hashmap_put(s
->writers
, w
->hashmap_key
?: key
, w
);
283 /**********************************************************************
284 **********************************************************************
285 **********************************************************************/
287 /* This should go away as soon as µhttpd allows state to be passed around. */
288 static RemoteServer
*server
;
290 static int dispatch_raw_source_event(sd_event_source
*event
,
294 static int dispatch_raw_source_until_block(sd_event_source
*event
,
296 static int dispatch_blocking_source_event(sd_event_source
*event
,
298 static int dispatch_raw_connection_event(sd_event_source
*event
,
302 static int dispatch_http_event(sd_event_source
*event
,
307 static int get_source_for_fd(RemoteServer
*s
,
308 int fd
, char *name
, RemoteSource
**source
) {
312 /* This takes ownership of name, but only on success. */
317 if (!GREEDY_REALLOC0(s
->sources
, s
->sources_size
, fd
+ 1))
320 r
= get_writer(s
, name
, &writer
);
322 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
325 if (s
->sources
[fd
] == NULL
) {
326 s
->sources
[fd
] = source_new(fd
, false, name
, writer
);
327 if (!s
->sources
[fd
]) {
328 writer_unref(writer
);
335 *source
= s
->sources
[fd
];
339 static int remove_source(RemoteServer
*s
, int fd
) {
340 RemoteSource
*source
;
343 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
345 source
= s
->sources
[fd
];
347 /* this closes fd too */
349 s
->sources
[fd
] = NULL
;
356 static int add_source(RemoteServer
*s
, int fd
, char* name
, bool own_name
) {
358 RemoteSource
*source
= NULL
;
361 /* This takes ownership of name, even on failure, if own_name is true. */
373 r
= get_source_for_fd(s
, fd
, name
, &source
);
375 log_error_errno(r
, "Failed to create source for fd:%d (%s): %m",
381 r
= sd_event_add_io(s
->events
, &source
->event
,
382 fd
, EPOLLIN
|EPOLLRDHUP
|EPOLLPRI
,
383 dispatch_raw_source_event
, source
);
385 /* Add additional source for buffer processing. It will be
387 r
= sd_event_add_defer(s
->events
, &source
->buffer_event
,
388 dispatch_raw_source_until_block
, source
);
390 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_OFF
);
391 } else if (r
== -EPERM
) {
392 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd
, name
);
393 r
= sd_event_add_defer(s
->events
, &source
->event
,
394 dispatch_blocking_source_event
, source
);
396 sd_event_source_set_enabled(source
->event
, SD_EVENT_ON
);
399 log_error_errno(r
, "Failed to register event source for fd:%d: %m",
404 r
= sd_event_source_set_description(source
->event
, name
);
406 log_error_errno(r
, "Failed to set source name for fd:%d: %m", fd
);
410 return 1; /* work to do */
413 remove_source(s
, fd
);
417 static int add_raw_socket(RemoteServer
*s
, int fd
) {
419 _cleanup_close_
int fd_
= fd
;
420 char name
[sizeof("raw-socket-")-1 + DECIMAL_STR_MAX(int) + 1];
424 r
= sd_event_add_io(s
->events
, &s
->listen_event
,
426 dispatch_raw_connection_event
, s
);
430 xsprintf(name
, "raw-socket-%d", fd
);
432 r
= sd_event_source_set_description(s
->listen_event
, name
);
441 static int setup_raw_socket(RemoteServer
*s
, const char *address
) {
444 fd
= make_socket_fd(LOG_INFO
, address
, SOCK_STREAM
| SOCK_CLOEXEC
);
448 return add_raw_socket(s
, fd
);
451 /**********************************************************************
452 **********************************************************************
453 **********************************************************************/
455 static int request_meta(void **connection_cls
, int fd
, char *hostname
) {
456 RemoteSource
*source
;
460 assert(connection_cls
);
464 r
= get_writer(server
, hostname
, &writer
);
466 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
469 source
= source_new(fd
, true, hostname
, writer
);
471 writer_unref(writer
);
475 log_debug("Added RemoteSource as connection metadata %p", source
);
477 *connection_cls
= source
;
481 static void request_meta_free(void *cls
,
482 struct MHD_Connection
*connection
,
483 void **connection_cls
,
484 enum MHD_RequestTerminationCode toe
) {
487 assert(connection_cls
);
491 log_debug("Cleaning up connection metadata %p", s
);
493 *connection_cls
= NULL
;
497 static int process_http_upload(
498 struct MHD_Connection
*connection
,
499 const char *upload_data
,
500 size_t *upload_data_size
,
501 RemoteSource
*source
) {
503 bool finished
= false;
509 log_trace("%s: connection %p, %zu bytes",
510 __func__
, connection
, *upload_data_size
);
512 if (*upload_data_size
) {
513 log_trace("Received %zu bytes", *upload_data_size
);
515 r
= push_data(source
, upload_data
, *upload_data_size
);
517 return mhd_respond_oom(connection
);
519 *upload_data_size
= 0;
524 r
= process_source(source
, arg_compress
, arg_seal
);
528 log_warning("Failed to process data for connection %p", connection
);
530 return mhd_respondf(connection
,
531 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
,
532 "Entry is too large, maximum is %u bytes.\n",
535 return mhd_respondf(connection
,
536 MHD_HTTP_UNPROCESSABLE_ENTITY
,
537 "Processing failed: %s.", strerror(-r
));
544 /* The upload is finished */
546 remaining
= source_non_empty(source
);
548 log_warning("Premature EOFbyte. %zu bytes lost.", remaining
);
549 return mhd_respondf(connection
, MHD_HTTP_EXPECTATION_FAILED
,
550 "Premature EOF. %zu bytes of trailing data not processed.",
554 return mhd_respond(connection
, MHD_HTTP_ACCEPTED
, "OK.\n");
557 static int request_handler(
559 struct MHD_Connection
*connection
,
563 const char *upload_data
,
564 size_t *upload_data_size
,
565 void **connection_cls
) {
569 _cleanup_free_
char *hostname
= NULL
;
572 assert(connection_cls
);
576 log_trace("Handling a connection %s %s %s", method
, url
, version
);
579 return process_http_upload(connection
,
580 upload_data
, upload_data_size
,
583 if (!streq(method
, "POST"))
584 return mhd_respond(connection
, MHD_HTTP_METHOD_NOT_ACCEPTABLE
,
585 "Unsupported method.\n");
587 if (!streq(url
, "/upload"))
588 return mhd_respond(connection
, MHD_HTTP_NOT_FOUND
,
591 header
= MHD_lookup_connection_value(connection
,
592 MHD_HEADER_KIND
, "Content-Type");
593 if (!header
|| !streq(header
, "application/vnd.fdo.journal"))
594 return mhd_respond(connection
, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE
,
595 "Content-Type: application/vnd.fdo.journal"
599 const union MHD_ConnectionInfo
*ci
;
601 ci
= MHD_get_connection_info(connection
,
602 MHD_CONNECTION_INFO_CONNECTION_FD
);
604 log_error("MHD_get_connection_info failed: cannot get remote fd");
605 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
606 "Cannot check remote address");
613 if (server
->check_trust
) {
614 r
= check_permissions(connection
, &code
, &hostname
);
618 r
= getnameinfo_pretty(fd
, &hostname
);
620 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
621 "Cannot check remote hostname");
626 r
= request_meta(connection_cls
, fd
, hostname
);
628 return respond_oom(connection
);
630 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
637 static int setup_microhttpd_server(RemoteServer
*s
,
642 struct MHD_OptionItem opts
[] = {
643 { MHD_OPTION_NOTIFY_COMPLETED
, (intptr_t) request_meta_free
},
644 { MHD_OPTION_EXTERNAL_LOGGER
, (intptr_t) microhttpd_logger
},
645 { MHD_OPTION_LISTEN_SOCKET
, fd
},
654 MHD_USE_EPOLL_LINUX_ONLY
|
655 MHD_USE_PEDANTIC_CHECKS
|
656 MHD_USE_PIPE_FOR_SHUTDOWN
;
658 const union MHD_DaemonInfo
*info
;
664 r
= fd_nonblock(fd
, true);
666 return log_error_errno(r
, "Failed to make fd:%d nonblocking: %m", fd
);
671 opts
[opts_pos
++] = (struct MHD_OptionItem
)
672 {MHD_OPTION_HTTPS_MEM_KEY
, 0, (char*) key
};
673 opts
[opts_pos
++] = (struct MHD_OptionItem
)
674 {MHD_OPTION_HTTPS_MEM_CERT
, 0, (char*) cert
};
676 flags
|= MHD_USE_SSL
;
679 opts
[opts_pos
++] = (struct MHD_OptionItem
)
680 {MHD_OPTION_HTTPS_MEM_TRUST
, 0, (char*) trust
};
683 d
= new(MHDDaemonWrapper
, 1);
687 d
->fd
= (uint64_t) fd
;
689 d
->daemon
= MHD_start_daemon(flags
, 0,
691 request_handler
, NULL
,
692 MHD_OPTION_ARRAY
, opts
,
695 log_error("Failed to start µhttp daemon");
700 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
701 key
? "HTTPS" : "HTTP", fd
, d
);
704 info
= MHD_get_daemon_info(d
->daemon
, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY
);
706 log_error("µhttp returned NULL daemon info");
711 epoll_fd
= info
->listen_fd
;
713 log_error("µhttp epoll fd is invalid");
718 r
= sd_event_add_io(s
->events
, &d
->event
,
720 dispatch_http_event
, d
);
722 log_error_errno(r
, "Failed to add event callback: %m");
726 r
= sd_event_source_set_description(d
->event
, "epoll-fd");
728 log_error_errno(r
, "Failed to set source name: %m");
732 r
= hashmap_ensure_allocated(&s
->daemons
, &uint64_hash_ops
);
738 r
= hashmap_put(s
->daemons
, &d
->fd
, d
);
740 log_error_errno(r
, "Failed to add daemon to hashmap: %m");
748 MHD_stop_daemon(d
->daemon
);
754 static int setup_microhttpd_socket(RemoteServer
*s
,
761 fd
= make_socket_fd(LOG_DEBUG
, address
, SOCK_STREAM
| SOCK_CLOEXEC
);
765 return setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
768 static int dispatch_http_event(sd_event_source
*event
,
772 MHDDaemonWrapper
*d
= userdata
;
777 r
= MHD_run(d
->daemon
);
779 log_error("MHD_run failed!");
780 // XXX: unregister daemon
784 return 1; /* work to do */
787 /**********************************************************************
788 **********************************************************************
789 **********************************************************************/
791 static int setup_signals(RemoteServer
*s
) {
796 assert_se(sigprocmask_many(SIG_SETMASK
, NULL
, SIGINT
, SIGTERM
, -1) >= 0);
798 r
= sd_event_add_signal(s
->events
, &s
->sigterm_event
, SIGTERM
, NULL
, s
);
802 r
= sd_event_add_signal(s
->events
, &s
->sigint_event
, SIGINT
, NULL
, s
);
809 static int negative_fd(const char *spec
) {
810 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
814 r
= safe_atoi(spec
, &fd
);
824 static int remoteserver_init(RemoteServer
*s
,
833 if ((arg_listen_raw
|| arg_listen_http
) && trust
) {
834 log_error("Option --trust makes all non-HTTPS connections untrusted.");
838 r
= sd_event_default(&s
->events
);
840 return log_error_errno(r
, "Failed to allocate event loop: %m");
844 assert(server
== NULL
);
847 r
= init_writer_hashmap(s
);
851 n
= sd_listen_fds(true);
853 return log_error_errno(n
, "Failed to read listening file descriptors from environment: %m");
855 log_debug("Received %d descriptors", n
);
857 if (MAX(http_socket
, https_socket
) >= SD_LISTEN_FDS_START
+ n
) {
858 log_error("Received fewer sockets than expected");
862 for (fd
= SD_LISTEN_FDS_START
; fd
< SD_LISTEN_FDS_START
+ n
; fd
++) {
863 if (sd_is_socket(fd
, AF_UNSPEC
, 0, true)) {
864 log_debug("Received a listening socket (fd:%d)", fd
);
866 if (fd
== http_socket
)
867 r
= setup_microhttpd_server(s
, fd
, NULL
, NULL
, NULL
);
868 else if (fd
== https_socket
)
869 r
= setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
871 r
= add_raw_socket(s
, fd
);
872 } else if (sd_is_socket(fd
, AF_UNSPEC
, 0, false)) {
875 r
= getnameinfo_pretty(fd
, &hostname
);
877 return log_error_errno(r
, "Failed to retrieve remote name: %m");
879 log_debug("Received a connection socket (fd:%d) from %s", fd
, hostname
);
881 r
= add_source(s
, fd
, hostname
, true);
883 log_error("Unknown socket passed on fd:%d", fd
);
889 return log_error_errno(r
, "Failed to register socket (fd:%d): %m",
894 const char *url
, *hostname
;
896 url
= strjoina(arg_url
, "/entries");
899 log_info("Spawning getter %s...", url
);
900 fd
= spawn_getter(arg_getter
, url
);
902 log_info("Spawning curl %s...", url
);
903 fd
= spawn_curl(url
);
909 startswith(arg_url
, "https://") ?:
910 startswith(arg_url
, "http://") ?:
913 r
= add_source(s
, fd
, (char*) hostname
, false);
918 if (arg_listen_raw
) {
919 log_debug("Listening on a socket...");
920 r
= setup_raw_socket(s
, arg_listen_raw
);
925 if (arg_listen_http
) {
926 r
= setup_microhttpd_socket(s
, arg_listen_http
, NULL
, NULL
, NULL
);
931 if (arg_listen_https
) {
932 r
= setup_microhttpd_socket(s
, arg_listen_https
, key
, cert
, trust
);
937 STRV_FOREACH(file
, arg_files
) {
938 const char *output_name
;
940 if (streq(*file
, "-")) {
941 log_debug("Using standard input as source.");
944 output_name
= "stdin";
946 log_debug("Reading file %s...", *file
);
948 fd
= open(*file
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
950 return log_error_errno(errno
, "Failed to open %s: %m", *file
);
954 r
= add_source(s
, fd
, (char*) output_name
, false);
959 if (s
->active
== 0) {
960 log_error("Zero sources specified");
964 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
) {
965 /* In this case we know what the writer will be
966 called, so we can create it and verify that we can
967 create output as expected. */
968 r
= get_writer(s
, NULL
, &s
->_single_writer
);
976 static void server_destroy(RemoteServer
*s
) {
980 while ((d
= hashmap_steal_first(s
->daemons
))) {
981 MHD_stop_daemon(d
->daemon
);
982 sd_event_source_unref(d
->event
);
986 hashmap_free(s
->daemons
);
988 assert(s
->sources_size
== 0 || s
->sources
);
989 for (i
= 0; i
< s
->sources_size
; i
++)
993 writer_unref(s
->_single_writer
);
994 hashmap_free(s
->writers
);
996 sd_event_source_unref(s
->sigterm_event
);
997 sd_event_source_unref(s
->sigint_event
);
998 sd_event_source_unref(s
->listen_event
);
999 sd_event_unref(s
->events
);
1001 /* fds that we're listening on remain open... */
1004 /**********************************************************************
1005 **********************************************************************
1006 **********************************************************************/
1008 static int handle_raw_source(sd_event_source
*event
,
1013 RemoteSource
*source
;
1016 /* Returns 1 if there might be more data pending,
1017 * 0 if data is currently exhausted, negative on error.
1020 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
1021 source
= s
->sources
[fd
];
1022 assert(source
->fd
== fd
);
1024 r
= process_source(source
, arg_compress
, arg_seal
);
1025 if (source
->state
== STATE_EOF
) {
1028 log_debug("EOF reached with source fd:%d (%s)",
1029 source
->fd
, source
->name
);
1031 remaining
= source_non_empty(source
);
1033 log_notice("Premature EOF. %zu bytes lost.", remaining
);
1034 remove_source(s
, source
->fd
);
1035 log_debug("%zu active sources remaining", s
->active
);
1037 } else if (r
== -E2BIG
) {
1038 log_notice_errno(E2BIG
, "Entry too big, skipped");
1040 } else if (r
== -EAGAIN
) {
1043 log_debug_errno(r
, "Closing connection: %m");
1044 remove_source(server
, fd
);
1050 static int dispatch_raw_source_until_block(sd_event_source
*event
,
1052 RemoteSource
*source
= userdata
;
1055 /* Make sure event stays around even if source is destroyed */
1056 sd_event_source_ref(event
);
1058 r
= handle_raw_source(event
, source
->fd
, EPOLLIN
, server
);
1060 /* No more data for now */
1061 sd_event_source_set_enabled(event
, SD_EVENT_OFF
);
1063 sd_event_source_unref(event
);
1068 static int dispatch_raw_source_event(sd_event_source
*event
,
1072 RemoteSource
*source
= userdata
;
1075 assert(source
->event
);
1076 assert(source
->buffer_event
);
1078 r
= handle_raw_source(event
, fd
, EPOLLIN
, server
);
1080 /* Might have more data. We need to rerun the handler
1081 * until we are sure the buffer is exhausted. */
1082 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_ON
);
1087 static int dispatch_blocking_source_event(sd_event_source
*event
,
1089 RemoteSource
*source
= userdata
;
1091 return handle_raw_source(event
, source
->fd
, EPOLLIN
, server
);
1094 static int accept_connection(const char* type
, int fd
,
1095 SocketAddress
*addr
, char **hostname
) {
1098 log_debug("Accepting new %s connection on fd:%d", type
, fd
);
1099 fd2
= accept4(fd
, &addr
->sockaddr
.sa
, &addr
->size
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
1101 return log_error_errno(errno
, "accept() on fd:%d failed: %m", fd
);
1103 switch(socket_address_family(addr
)) {
1106 _cleanup_free_
char *a
= NULL
;
1109 r
= socket_address_print(addr
, &a
);
1111 log_error_errno(r
, "socket_address_print(): %m");
1116 r
= socknameinfo_pretty(&addr
->sockaddr
, addr
->size
, &b
);
1118 log_error_errno(r
, "Resolving hostname failed: %m");
1123 log_debug("Accepted %s %s connection from %s",
1125 socket_address_family(addr
) == AF_INET
? "IP" : "IPv6",
1133 log_error("Rejected %s connection with unsupported family %d",
1134 type
, socket_address_family(addr
));
1141 static int dispatch_raw_connection_event(sd_event_source
*event
,
1145 RemoteServer
*s
= userdata
;
1147 SocketAddress addr
= {
1148 .size
= sizeof(union sockaddr_union
),
1149 .type
= SOCK_STREAM
,
1151 char *hostname
= NULL
;
1153 fd2
= accept_connection("raw", fd
, &addr
, &hostname
);
1157 return add_source(s
, fd2
, hostname
, true);
1160 /**********************************************************************
1161 **********************************************************************
1162 **********************************************************************/
1164 static const char* const journal_write_split_mode_table
[_JOURNAL_WRITE_SPLIT_MAX
] = {
1165 [JOURNAL_WRITE_SPLIT_NONE
] = "none",
1166 [JOURNAL_WRITE_SPLIT_HOST
] = "host",
1169 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode
, JournalWriteSplitMode
);
1170 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode
,
1171 journal_write_split_mode
,
1172 JournalWriteSplitMode
,
1173 "Failed to parse split mode setting");
1175 static int parse_config(void) {
1176 const ConfigTableItem items
[] = {
1177 { "Remote", "SplitMode", config_parse_write_split_mode
, 0, &arg_split_mode
},
1178 { "Remote", "ServerKeyFile", config_parse_path
, 0, &arg_key
},
1179 { "Remote", "ServerCertificateFile", config_parse_path
, 0, &arg_cert
},
1180 { "Remote", "TrustedCertificateFile", config_parse_path
, 0, &arg_trust
},
1183 return config_parse_many(PKGSYSCONFDIR
"/journal-remote.conf",
1184 CONF_DIRS_NULSTR("systemd/journal-remote.conf"),
1185 "Remote\0", config_item_table_lookup
, items
,
1189 static void help(void) {
1190 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1191 "Write external journal events to journal file(s).\n\n"
1192 " -h --help Show this help\n"
1193 " --version Show package version\n"
1194 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1195 " --getter=COMMAND Read events from the output of COMMAND\n"
1196 " --listen-raw=ADDR Listen for connections at ADDR\n"
1197 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1198 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1199 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1200 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1201 " --seal[=BOOL] Use event sealing (default: no)\n"
1202 " --key=FILENAME SSL key in PEM format (default:\n"
1203 " \"" PRIV_KEY_FILE
"\")\n"
1204 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1205 " \"" CERT_FILE
"\")\n"
1206 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1207 " \"" TRUST_FILE
"\")\n"
1208 " --gnutls-log=CATEGORY...\n"
1209 " Specify a list of gnutls logging categories\n"
1210 " --split-mode=none|host How many output files to create\n"
1212 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1213 , program_invocation_short_name
);
1216 static int parse_argv(int argc
, char *argv
[]) {
1218 ARG_VERSION
= 0x100,
1233 static const struct option options
[] = {
1234 { "help", no_argument
, NULL
, 'h' },
1235 { "version", no_argument
, NULL
, ARG_VERSION
},
1236 { "url", required_argument
, NULL
, ARG_URL
},
1237 { "getter", required_argument
, NULL
, ARG_GETTER
},
1238 { "listen-raw", required_argument
, NULL
, ARG_LISTEN_RAW
},
1239 { "listen-http", required_argument
, NULL
, ARG_LISTEN_HTTP
},
1240 { "listen-https", required_argument
, NULL
, ARG_LISTEN_HTTPS
},
1241 { "output", required_argument
, NULL
, 'o' },
1242 { "split-mode", required_argument
, NULL
, ARG_SPLIT_MODE
},
1243 { "compress", optional_argument
, NULL
, ARG_COMPRESS
},
1244 { "seal", optional_argument
, NULL
, ARG_SEAL
},
1245 { "key", required_argument
, NULL
, ARG_KEY
},
1246 { "cert", required_argument
, NULL
, ARG_CERT
},
1247 { "trust", required_argument
, NULL
, ARG_TRUST
},
1248 { "gnutls-log", required_argument
, NULL
, ARG_GNUTLS_LOG
},
1253 bool type_a
, type_b
;
1258 while ((c
= getopt_long(argc
, argv
, "ho:", options
, NULL
)) >= 0)
1262 return 0 /* done */;
1269 log_error("cannot currently set more than one --url");
1278 log_error("cannot currently use --getter more than once");
1282 arg_getter
= optarg
;
1285 case ARG_LISTEN_RAW
:
1286 if (arg_listen_raw
) {
1287 log_error("cannot currently use --listen-raw more than once");
1291 arg_listen_raw
= optarg
;
1294 case ARG_LISTEN_HTTP
:
1295 if (arg_listen_http
|| http_socket
>= 0) {
1296 log_error("cannot currently use --listen-http more than once");
1300 r
= negative_fd(optarg
);
1304 arg_listen_http
= optarg
;
1307 case ARG_LISTEN_HTTPS
:
1308 if (arg_listen_https
|| https_socket
>= 0) {
1309 log_error("cannot currently use --listen-https more than once");
1313 r
= negative_fd(optarg
);
1317 arg_listen_https
= optarg
;
1323 log_error("Key file specified twice");
1327 arg_key
= strdup(optarg
);
1335 log_error("Certificate file specified twice");
1339 arg_cert
= strdup(optarg
);
1346 if (arg_trust
|| arg_trust_all
) {
1347 log_error("Confusing trusted CA configuration");
1351 if (streq(optarg
, "all"))
1352 arg_trust_all
= true;
1355 arg_trust
= strdup(optarg
);
1359 log_error("Option --trust is not available.");
1368 log_error("cannot use --output/-o more than once");
1372 arg_output
= optarg
;
1375 case ARG_SPLIT_MODE
:
1376 arg_split_mode
= journal_write_split_mode_from_string(optarg
);
1377 if (arg_split_mode
== _JOURNAL_WRITE_SPLIT_INVALID
) {
1378 log_error("Invalid split mode: %s", optarg
);
1385 r
= parse_boolean(optarg
);
1387 log_error("Failed to parse --compress= parameter.");
1393 arg_compress
= true;
1399 r
= parse_boolean(optarg
);
1401 log_error("Failed to parse --seal= parameter.");
1411 case ARG_GNUTLS_LOG
: {
1413 const char *word
, *state
;
1416 FOREACH_WORD_SEPARATOR(word
, size
, optarg
, ",", state
) {
1419 cat
= strndup(word
, size
);
1423 if (strv_consume(&arg_gnutls_log
, cat
) < 0)
1428 log_error("Option --gnutls-log is not available.");
1437 assert_not_reached("Unknown option code.");
1441 arg_files
= argv
+ optind
;
1443 type_a
= arg_getter
|| !strv_isempty(arg_files
);
1446 || arg_listen_http
|| arg_listen_https
1447 || sd_listen_fds(false) > 0;
1448 if (type_a
&& type_b
) {
1449 log_error("Cannot use file input or --getter with "
1450 "--arg-listen-... or socket activation.");
1455 log_error("Option --output must be specified with file input or --getter.");
1459 arg_split_mode
= JOURNAL_WRITE_SPLIT_NONE
;
1462 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
1463 && arg_output
&& is_dir(arg_output
, true) > 0) {
1464 log_error("For SplitMode=none, output must be a file.");
1468 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
1469 && arg_output
&& is_dir(arg_output
, true) <= 0) {
1470 log_error("For SplitMode=host, output must be a directory.");
1474 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1475 journal_write_split_mode_to_string(arg_split_mode
),
1480 return 1 /* work to do */;
1483 static int load_certificates(char **key
, char **cert
, char **trust
) {
1486 r
= read_full_file(arg_key
?: PRIV_KEY_FILE
, key
, NULL
);
1488 return log_error_errno(r
, "Failed to read key from file '%s': %m",
1489 arg_key
?: PRIV_KEY_FILE
);
1491 r
= read_full_file(arg_cert
?: CERT_FILE
, cert
, NULL
);
1493 return log_error_errno(r
, "Failed to read certificate from file '%s': %m",
1494 arg_cert
?: CERT_FILE
);
1497 log_info("Certificate checking disabled.");
1499 r
= read_full_file(arg_trust
?: TRUST_FILE
, trust
, NULL
);
1501 return log_error_errno(r
, "Failed to read CA certificate file '%s': %m",
1502 arg_trust
?: TRUST_FILE
);
1508 int main(int argc
, char **argv
) {
1509 RemoteServer s
= {};
1511 _cleanup_free_
char *key
= NULL
, *cert
= NULL
, *trust
= NULL
;
1513 log_show_color(true);
1514 log_parse_environment();
1518 return EXIT_FAILURE
;
1520 r
= parse_argv(argc
, argv
);
1522 return r
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;
1525 if (arg_listen_http
|| arg_listen_https
) {
1526 r
= setup_gnutls_logger(arg_gnutls_log
);
1528 return EXIT_FAILURE
;
1531 if (arg_listen_https
|| https_socket
>= 0)
1532 if (load_certificates(&key
, &cert
, &trust
) < 0)
1533 return EXIT_FAILURE
;
1535 if (remoteserver_init(&s
, key
, cert
, trust
) < 0)
1536 return EXIT_FAILURE
;
1538 r
= sd_event_set_watchdog(s
.events
, true);
1540 log_error_errno(r
, "Failed to enable watchdog: %m");
1542 log_debug("Watchdog is %s.", r
> 0 ? "enabled" : "disabled");
1544 log_debug("%s running as pid "PID_FMT
,
1545 program_invocation_short_name
, getpid());
1548 "STATUS=Processing requests...");
1551 r
= sd_event_get_state(s
.events
);
1554 if (r
== SD_EVENT_FINISHED
)
1557 r
= sd_event_run(s
.events
, -1);
1559 log_error_errno(r
, "Failed to run event loop: %m");
1566 "STATUS=Shutting down after writing %" PRIu64
" entries...", s
.event_count
);
1567 log_info("Finishing after writing %" PRIu64
" entries", s
.event_count
);
1575 return r
>= 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;