journal-remote.c revision 7449bc1f34c206e3ff8e274cd74e2db950d492a1
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering This file is part of systemd.
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering Copyright 2012 Zbigniew Jędrzejewski-Szmek
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering systemd is free software; you can redistribute it and/or modify it
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering under the terms of the GNU Lesser General Public License as published by
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering (at your option) any later version.
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering systemd is distributed in the hope that it will be useful, but
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering Lesser General Public License for more details.
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering You should have received a copy of the GNU Lesser General Public License
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#define REMOTE_JOURNAL_PATH "/var/log/journal/" SD_ID128_FORMAT_STR "/remote-%s.journal"
9f6445e34a57c270f013c9416c123e56261553ddLennart Poetteringstatic int arg_compress = true;
507f22bd0172bff5e5d98145b1419bd472a2c57fZbigniew Jędrzejewski-Szmekstatic int arg_seal = false;
507f22bd0172bff5e5d98145b1419bd472a2c57fZbigniew Jędrzejewski-Szmekstatic int http_socket = -1, https_socket = -1;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering/**********************************************************************
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering **********************************************************************
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering **********************************************************************/
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int spawn_child(const char* child, char** argv) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_error("Failed to create pager pipe: %m");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering /* In the child */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_error("Failed to dup pipe to stdout: %m");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering /* Make sure the child goes away when the parent dies */
baed47c3c20512507e497058d388782400a072f6Lennart Poettering if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering /* Check whether our parent died before we were able
baed47c3c20512507e497058d388782400a072f6Lennart Poettering * to set the death signal */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_error("Failed to exec child %s: %m", child);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_warning("Failed to close write end of pipe: %m");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering "--show-error",
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int spawn_getter(char *getter, char *url) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_error("Failed to spawn getter %s: %m", getter);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int open_output(Writer *s, const char* url) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering _cleanup_free_ char *name, *output = NULL;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering for(c = name; *c; c++) {
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering else if (*c == '?') {
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering log_error("failed to determine machine ID128: %s", strerror(-r));
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering r = asprintf(&output, REMOTE_JOURNAL_PATH,
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering "%s/remote-%s.journal", arg_output, name);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_error("Failed to open output journal %s: %s",
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_info("Opened output file %s", s->journal->path);
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering/**********************************************************************
baed47c3c20512507e497058d388782400a072f6Lennart Poettering **********************************************************************
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering **********************************************************************/
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering sd_event_source *sigterm_event, *sigint_event, *listen_event;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering/* This should go away as soon as µhttpd allows state to be passed around. */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int dispatch_raw_source_event(sd_event_source *event,
5996c7c295e073ce21d41305169132c8aa993ad0Lennart Poetteringstatic int dispatch_raw_connection_event(sd_event_source *event,
5996c7c295e073ce21d41305169132c8aa993ad0Lennart Poetteringstatic int dispatch_http_event(sd_event_source *event,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int get_source_for_fd(RemoteServer *s, int fd, RemoteSource **source) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int remove_source(RemoteServer *s, int fd) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering assert(fd >= 0 && fd < (ssize_t) s->sources_size);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int add_source(RemoteServer *s, int fd, const char* name) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("Creating source for fd:%d (%s)", fd, realname);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_error("Failed to create source for fd:%d (%s)", fd, realname);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = sd_event_add_io(s->events, &source->event,
baed47c3c20512507e497058d388782400a072f6Lennart Poettering fd, EPOLLIN, dispatch_raw_source_event, s);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_error("Failed to register event source for fd:%d: %s",
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int add_raw_socket(RemoteServer *s, int fd) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = sd_event_add_io(s->events, &s->listen_event, fd, EPOLLIN,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int setup_raw_socket(RemoteServer *s, const char *address) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering/**********************************************************************
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering **********************************************************************
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering **********************************************************************/
baed47c3c20512507e497058d388782400a072f6Lennart Poetteringstatic RemoteSource *request_meta(void **connection_cls) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("Added RemoteSource as connection metadata %p", source);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("Cleaning up connection metadata %p", s);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("request_handler_upload: connection %p, %zu bytes",
baed47c3c20512507e497058d388782400a072f6Lennart Poettering log_info("Received %zu bytes", *upload_data_size);
b7c9ae91d111b3e89d1ffc00e08f9ed97a8ff5dbLennart Poettering r = push_data(source, upload_data, *upload_data_size);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering while (true) {
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering r = process_source(source, &server->writer, arg_compress, arg_seal);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering else if (r < 0) {
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering log_warning("Failed to process data for connection %p", connection);
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering "Entry is too large, maximum is %u bytes.\n",
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering /* The upload is finished */
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering log_warning("EOF reached with incomplete data");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return mhd_respond(connection, MHD_HTTP_EXPECTATION_FAILED,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering "Trailing data not processed.");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
5996c7c295e073ce21d41305169132c8aa993ad0Lennart Poettering log_debug("Handling a connection %s %s %s", method, url, version);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
5996c7c295e073ce21d41305169132c8aa993ad0Lennart Poettering "Unsupported method.\n");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering "Not found.\n");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering header = MHD_lookup_connection_value(connection,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (!header || !streq(header, "application/vnd.fdo.journal"))
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
4da416aa20b956571d74720bc91222881443e24bLennart Poettering "Content-Type: application/vnd.fdo.journal"
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering " is required.\n");
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering r = check_permissions(connection, &code);
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poetteringstatic int setup_microhttpd_server(RemoteServer *s, int fd, bool https) {
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering log_error("Failed to make fd:%d nonblocking: %s", fd, strerror(-r));
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering opts[opts_pos++] = (struct MHD_OptionItem)
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering opts[opts_pos++] = (struct MHD_OptionItem)
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering {MHD_OPTION_HTTPS_MEM_CERT, 0, cert_pem};
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering opts[opts_pos++] = (struct MHD_OptionItem)
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering {MHD_OPTION_HTTPS_MEM_TRUST, 0, trust_pem};
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering log_error("Failed to start µhttp daemon");
if (!info) {
r = -ENOTSUP;
goto error;
if (epoll_fd < 0) {
r = -EUCLEAN;
goto error;
goto error;
log_oom();
goto error;
goto error;
s->active ++;
free(d);
const char *address,
bool https) {
int fd;
if (fd < 0)
return fd;
int fd,
void *userdata) {
assert(d);
if (r == MHD_NO) {
return -EINVAL;
void *userdata) {
assert(s);
assert(s);
int fd, r;
if (fd >= 0)
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)