journal-remote.c revision 5c879495eab608bf9b6e7bec1020d916a0503b6e
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2012 Zbigniew Jędrzejewski-Szmek
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU Lesser General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Lesser General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU Lesser General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
818f766b12e025683cf4fed12b3da2a025bb0b31Lennart Poettering#define REMOTE_JOURNAL_PATH "/var/log/journal/" SD_ID128_FORMAT_STR "/remote-%s.journal"
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringstatic int arg_compress = true;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int arg_seal = false;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int http_socket = -1, https_socket = -1;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering/**********************************************************************
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering **********************************************************************
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering **********************************************************************/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int spawn_child(const char* child, char** argv) {
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering log_error("Failed to create pager pipe: %m");
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering /* In the child */
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering log_error("Failed to dup pipe to stdout: %m");
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering /* Make sure the child goes away when the parent dies */
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering /* Check whether our parent died before we were able
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering * to set the death signal */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering log_error("Failed to exec child %s: %m", child);
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering log_warning("Failed to close write end of pipe: %m");
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering "--show-error",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int spawn_getter(char *getter, char *url) {
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering log_error("Failed to spawn getter %s: %m", getter);
3339cb71d44c5198f9546f113674f06dc7b01a6fLennart Poetteringstatic int open_output(Writer *s, const char* url) {
3339cb71d44c5198f9546f113674f06dc7b01a6fLennart Poettering _cleanup_free_ char *name, *output = NULL;
3339cb71d44c5198f9546f113674f06dc7b01a6fLennart Poettering for(c = name; *c; c++) {
3339cb71d44c5198f9546f113674f06dc7b01a6fLennart Poettering else if (*c == '?') {
3339cb71d44c5198f9546f113674f06dc7b01a6fLennart Poettering log_error("failed to determine machine ID128: %s", strerror(-r));
3339cb71d44c5198f9546f113674f06dc7b01a6fLennart Poettering r = asprintf(&output, REMOTE_JOURNAL_PATH,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "%s/remote-%s.journal", arg_output, name);
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering log_error("Failed to open output journal %s: %s",
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering log_info("Opened output file %s", s->journal->path);
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering/**********************************************************************
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering **********************************************************************
309e9d86f0e7f9c5f0a2a09227bdfdb3174d4436Lennart Poettering **********************************************************************/
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering sd_event_source *sigterm_event, *sigint_event, *listen_event;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/* This should go away as soon as µhttpd allows state to be passed around. */
ad867662936a4c7ab2c7116d804c272338801231Lennart Poetteringstatic int dispatch_raw_source_event(sd_event_source *event,
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int dispatch_raw_connection_event(sd_event_source *event,
ad867662936a4c7ab2c7116d804c272338801231Lennart Poetteringstatic int dispatch_http_event(sd_event_source *event,
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poetteringstatic int get_source_for_fd(RemoteServer *s, int fd, RemoteSource **source) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int remove_source(RemoteServer *s, int fd) {
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering assert(fd >= 0 && fd < (ssize_t) s->sources_size);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int add_source(RemoteServer *s, int fd, const char* name) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_debug("Creating source for fd:%d (%s)", fd, realname);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_error("Failed to create source for fd:%d (%s)", fd, realname);
82bd6dddc4a363a9c3c6f41eb46eb171a80dca27Lennart Poettering r = sd_event_add_io(s->events, &source->event,
82bd6dddc4a363a9c3c6f41eb46eb171a80dca27Lennart Poettering fd, EPOLLIN, dispatch_raw_source_event, s);
82bd6dddc4a363a9c3c6f41eb46eb171a80dca27Lennart Poettering log_error("Failed to register event source for fd:%d: %s",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int add_raw_socket(RemoteServer *s, int fd) {
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering r = sd_event_add_io(s->events, &s->listen_event, fd, EPOLLIN,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int setup_raw_socket(RemoteServer *s, const char *address) {
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
3339cb71d44c5198f9546f113674f06dc7b01a6fLennart Poettering/**********************************************************************
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering **********************************************************************
3339cb71d44c5198f9546f113674f06dc7b01a6fLennart Poettering **********************************************************************/
3339cb71d44c5198f9546f113674f06dc7b01a6fLennart Poetteringstatic RemoteSource *request_meta(void **connection_cls) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_debug("Added RemoteSource as connection metadata %p", source);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_debug("Cleaning up connection metadata %p", s);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_debug("request_handler_upload: connection %p, %zu bytes",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_info("Received %zu bytes", *upload_data_size);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = push_data(source, upload_data, *upload_data_size);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_error("Failed to store received data of size %zu: %s",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering while (true) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = process_source(source, &server->writer, arg_compress, arg_seal);
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering else if (r == -EAGAIN || r == -EWOULDBLOCK)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering else if (r < 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_warning("Failed to process data for connection %p", connection);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return mhd_respondf(connection, MHD_HTTP_UNPROCESSABLE_ENTITY,
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering /* The upload is finished */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering log_warning("EOF reached with incomplete data");
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return mhd_respond(connection, MHD_HTTP_EXPECTATION_FAILED,
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "Trailing data not processed.");
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_debug("Handling a connection %s %s %s", method, url, version);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "Unsupported method.\n");
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering "Not found.\n");
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering header = MHD_lookup_connection_value(connection,
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering if (!header || !streq(header, "application/vnd.fdo.journal"))
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering "Content-Type: application/vnd.fdo.journal"
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering " is required.\n");
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering r = check_permissions(connection, &code);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poetteringstatic int setup_microhttpd_server(RemoteServer *s, int fd, bool https) {
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering log_error("Failed to make fd:%d nonblocking: %s", fd, strerror(-r));
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering opts[opts_pos++] = (struct MHD_OptionItem)
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering opts[opts_pos++] = (struct MHD_OptionItem)
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering {MHD_OPTION_HTTPS_MEM_CERT, 0, cert_pem};
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering opts[opts_pos++] = (struct MHD_OptionItem)
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering {MHD_OPTION_HTTPS_MEM_TRUST, 0, trust_pem};
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering log_error("Failed to start µhttp daemon");
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering log_error("µhttp returned NULL daemon info");
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering r = sd_event_add_io(s->events, &d->event,
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering epoll_fd, EPOLLIN, dispatch_http_event, d);
7b9f7afcc04e80b77a2567b0750aa2cd03c1a1cdLennart Poettering log_error("Failed to add event callback: %s", strerror(-r));
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering r = hashmap_ensure_allocated(&s->daemons, uint64_hash_func, uint64_compare_func);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering log_error("Failed to add daemon to hashmap: %s", strerror(-r));
82bd6dddc4a363a9c3c6f41eb46eb171a80dca27Lennart Poetteringstatic int setup_microhttpd_socket(RemoteServer *s,
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering return setup_microhttpd_server(s, fd, https);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poetteringstatic int dispatch_http_event(sd_event_source *event,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering // XXX: unregister daemon
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/**********************************************************************
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering **********************************************************************
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering **********************************************************************/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int dispatch_sigterm(sd_event_source *event,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int setup_signals(RemoteServer *s) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering sigset_add_many(&mask, SIGINT, SIGTERM, -1);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, dispatch_sigterm, s);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, dispatch_sigterm, s);
return -ENOENT;
return -fd;
int r, n, fd;
char **file;
assert(s);
setup_signals(s);
server = s;
n = sd_listen_fds(true);
strerror(-n));
return -EBADFD;
return -EINVAL;
if (arg_url) {
if (!urlv)
return log_oom();
if (!url)
return log_oom();
if (arg_getter) {
if (fd < 0)
return fd;
if (arg_listen_raw) {
if (arg_listen_http) {
if (arg_listen_https) {
if (fd < 0) {
return -errno;
if (s->active == 0) {
return -EINVAL;
size_t i;
MHDDaemonWrapper *d;
free(d);
for (i = 0; i < s->sources_size; i++)
remove_source(s, i);
int fd,
void *userdata) {
} else if (r == -E2BIG) {
int fd2, r;
if (fd2 < 0) {
return -errno;
case AF_INET:
case AF_INET6: {
type,
return fd2;
return -EINVAL;
int fd,
void *userdata) {
int fd2;
if (fd2 < 0)
return fd2;
static void help(void) {
help();
case ARG_VERSION:
case ARG_URL:
if (arg_url) {
return -EINVAL;
case ARG_GETTER:
if (arg_getter) {
return -EINVAL;
case ARG_LISTEN_RAW:
if (arg_listen_raw) {
return -EINVAL;
case ARG_LISTEN_HTTP:
return -EINVAL;
http_socket = r;
else if (r == -ENOENT)
return -EINVAL;
case ARG_LISTEN_HTTPS:
return -EINVAL;
https_socket = r;
else if (r == -ENOENT)
return -EINVAL;
case ARG_KEY:
if (key_pem) {
return -EINVAL;
case ARG_CERT:
if (cert_pem) {
return -EINVAL;
case ARG_TRUST:
#ifdef HAVE_GNUTLS
if (trust_pem) {
return -EINVAL;
return -EINVAL;
if (arg_output) {
return -EINVAL;
case ARG_COMPRESS:
arg_compress = true;
case ARG_NO_COMPRESS:
arg_compress = false;
case ARG_SEAL:
arg_seal = true;
case ARG_NO_SEAL:
arg_seal = false;
case ARG_GNUTLS_LOG: {
#ifdef HAVE_GNUTLS
char *cat;
if (!cat)
return log_oom();
return log_oom();
return -EINVAL;
return -EINVAL;
return -EINVAL;
return -EINVAL;
#ifdef HAVE_GNUTLS
char **cat;
if (categories)
RemoteServer s = {};
int r, r2;
log_show_color(true);
return EXIT_FAILURE;
if (remoteserver_init(&s) < 0)
return EXIT_FAILURE;
sd_notify(false,
while (s.active) {
if (r == SD_EVENT_FINISHED)