journal-remote.c revision 7449bc1f34c206e3ff8e274cd74e2db950d492a1
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering/***
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering This file is part of systemd.
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering Copyright 2012 Zbigniew Jędrzejewski-Szmek
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
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
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
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***/
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include <errno.h>
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include <fcntl.h>
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include <inttypes.h>
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include <stdio.h>
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include <stdlib.h>
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include <string.h>
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include <sys/prctl.h>
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include <sys/socket.h>
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include <sys/stat.h>
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include <sys/types.h>
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include <unistd.h>
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include <getopt.h>
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include "sd-daemon.h"
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include "sd-event.h"
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include "journal-file.h"
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include "journald-native.h"
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include "socket-util.h"
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include "mkdir.h"
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include "build.h"
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include "macro.h"
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include "strv.h"
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include "fileio.h"
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include "microhttpd-util.h"
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#ifdef HAVE_GNUTLS
baed47c3c20512507e497058d388782400a072f6Lennart Poettering#include <gnutls/gnutls.h>
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#endif
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include "journal-remote-parse.h"
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#include "journal-remote-write.h"
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#define REMOTE_JOURNAL_PATH "/var/log/journal/" SD_ID128_FORMAT_STR "/remote-%s.journal"
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic char* arg_output = NULL;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic char* arg_url = NULL;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic char* arg_getter = NULL;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic char* arg_listen_raw = NULL;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic char* arg_listen_http = NULL;
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poetteringstatic char* arg_listen_https = NULL;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic char** arg_files = NULL;
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;
e627440b41bb0284e4892f7aa9d84c77972487e2Lennart Poetteringstatic char** arg_gnutls_log = NULL;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic char *key_pem = NULL;
5996c7c295e073ce21d41305169132c8aa993ad0Lennart Poetteringstatic char *cert_pem = NULL;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic char *trust_pem = NULL;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering/**********************************************************************
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering **********************************************************************
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering **********************************************************************/
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int spawn_child(const char* child, char** argv) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering int fd[2];
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering pid_t parent_pid, child_pid;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering int r;
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (pipe(fd) < 0) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_error("Failed to create pager pipe: %m");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return -errno;
baed47c3c20512507e497058d388782400a072f6Lennart Poettering }
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering parent_pid = getpid();
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering child_pid = fork();
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (child_pid < 0) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = -errno;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_error("Failed to fork: %m");
b7c9ae91d111b3e89d1ffc00e08f9ed97a8ff5dbLennart Poettering safe_close_pair(fd);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering }
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering /* In the child */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (child_pid == 0) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = dup2(fd[1], STDOUT_FILENO);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (r < 0) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_error("Failed to dup pipe to stdout: %m");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering _exit(EXIT_FAILURE);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering }
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering safe_close_pair(fd);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering /* Make sure the child goes away when the parent dies */
baed47c3c20512507e497058d388782400a072f6Lennart Poettering if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
baed47c3c20512507e497058d388782400a072f6Lennart Poettering _exit(EXIT_FAILURE);
15411c0cb1192799b37ec8f25d6f30e8d7292fc6David Herrmann
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering /* Check whether our parent died before we were able
baed47c3c20512507e497058d388782400a072f6Lennart Poettering * to set the death signal */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (getppid() != parent_pid)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering _exit(EXIT_SUCCESS);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering
baed47c3c20512507e497058d388782400a072f6Lennart Poettering execvp(child, argv);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_error("Failed to exec child %s: %m", child);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering _exit(EXIT_FAILURE);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering }
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = close(fd[1]);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering if (r < 0)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_warning("Failed to close write end of pipe: %m");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return fd[0];
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering}
baed47c3c20512507e497058d388782400a072f6Lennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int spawn_curl(char* url) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering char **argv = STRV_MAKE("curl",
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering "-HAccept: application/vnd.fdo.journal",
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering "--silent",
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering "--show-error",
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering url);
b7c9ae91d111b3e89d1ffc00e08f9ed97a8ff5dbLennart Poettering int r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = spawn_child("curl", argv);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (r < 0)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_error("Failed to spawn curl: %m");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering}
baed47c3c20512507e497058d388782400a072f6Lennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int spawn_getter(char *getter, char *url) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering int r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering _cleanup_strv_free_ char **words = NULL;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering assert(getter);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering words = strv_split_quoted(getter);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (!words)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return log_oom();
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = spawn_child(words[0], words);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (r < 0)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_error("Failed to spawn getter %s: %m", getter);
b7c9ae91d111b3e89d1ffc00e08f9ed97a8ff5dbLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return r;
507f22bd0172bff5e5d98145b1419bd472a2c57fZbigniew Jędrzejewski-Szmek}
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int open_output(Writer *s, const char* url) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering _cleanup_free_ char *name, *output = NULL;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering char *c;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering int r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering assert(url);
b7c9ae91d111b3e89d1ffc00e08f9ed97a8ff5dbLennart Poettering name = strdup(url);
b7c9ae91d111b3e89d1ffc00e08f9ed97a8ff5dbLennart Poettering if (!name)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return log_oom();
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering for(c = name; *c; c++) {
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering if (*c == '/' || *c == ':' || *c == ' ')
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering *c = '~';
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering else if (*c == '?') {
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering *c = '\0';
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering break;
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering }
baed47c3c20512507e497058d388782400a072f6Lennart Poettering }
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering if (!arg_output) {
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering sd_id128_t machine;
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering r = sd_id128_get_machine(&machine);
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering if (r < 0) {
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering log_error("failed to determine machine ID128: %s", strerror(-r));
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering return r;
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering }
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering r = asprintf(&output, REMOTE_JOURNAL_PATH,
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering SD_ID128_FORMAT_VAL(machine), name);
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering if (r < 0)
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering return log_oom();
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering } else {
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering r = is_dir(arg_output, true);
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering if (r > 0) {
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering r = asprintf(&output,
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering "%s/remote-%s.journal", arg_output, name);
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering if (r < 0)
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering return log_oom();
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering } else {
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering output = strdup(arg_output);
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering if (!output)
507f22bd0172bff5e5d98145b1419bd472a2c57fZbigniew Jędrzejewski-Szmek return log_oom();
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering }
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering }
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering r = journal_file_open_reliably(output,
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering O_RDWR|O_CREAT, 0640,
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering arg_compress, arg_seal,
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering &s->metrics,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering s->mmap,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering NULL, &s->journal);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (r < 0)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_error("Failed to open output journal %s: %s",
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering arg_output, strerror(-r));
baed47c3c20512507e497058d388782400a072f6Lennart Poettering else
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_info("Opened output file %s", s->journal->path);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return r;
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering}
671e021c92c835c6c701dc61463149d05b6f31afLennart Poettering
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering/**********************************************************************
baed47c3c20512507e497058d388782400a072f6Lennart Poettering **********************************************************************
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering **********************************************************************/
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringtypedef struct MHDDaemonWrapper {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering uint64_t fd;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering struct MHD_Daemon *daemon;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering sd_event_source *event;
baed47c3c20512507e497058d388782400a072f6Lennart Poettering} MHDDaemonWrapper;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringtypedef struct RemoteServer {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering RemoteSource **sources;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering size_t sources_size;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering size_t active;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
7851983162ef851d5b9ce12bd88de86fc402f88aMichal Schmidt sd_event *events;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering sd_event_source *sigterm_event, *sigint_event, *listen_event;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering Writer writer;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
baed47c3c20512507e497058d388782400a072f6Lennart Poettering Hashmap *daemons;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering} RemoteServer;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering/* This should go away as soon as µhttpd allows state to be passed around. */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic RemoteServer *server;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int dispatch_raw_source_event(sd_event_source *event,
5996c7c295e073ce21d41305169132c8aa993ad0Lennart Poettering int fd,
5996c7c295e073ce21d41305169132c8aa993ad0Lennart Poettering uint32_t revents,
5996c7c295e073ce21d41305169132c8aa993ad0Lennart Poettering void *userdata);
5996c7c295e073ce21d41305169132c8aa993ad0Lennart Poetteringstatic int dispatch_raw_connection_event(sd_event_source *event,
5996c7c295e073ce21d41305169132c8aa993ad0Lennart Poettering int fd,
d05089d86ef032b245c7f928e623b88c82998ab0Michal Schmidt uint32_t revents,
5996c7c295e073ce21d41305169132c8aa993ad0Lennart Poettering void *userdata);
5996c7c295e073ce21d41305169132c8aa993ad0Lennart Poetteringstatic int dispatch_http_event(sd_event_source *event,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering int fd,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering uint32_t revents,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering void *userdata);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int get_source_for_fd(RemoteServer *s, int fd, RemoteSource **source) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering assert(fd >= 0);
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering assert(source);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return log_oom();
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
3c1668da6202f1ead3d4d3981b89e9da1a0e98e3Lennart Poettering if (s->sources[fd] == NULL) {
3c1668da6202f1ead3d4d3981b89e9da1a0e98e3Lennart Poettering s->sources[fd] = new0(RemoteSource, 1);
3c1668da6202f1ead3d4d3981b89e9da1a0e98e3Lennart Poettering if (!s->sources[fd])
3c1668da6202f1ead3d4d3981b89e9da1a0e98e3Lennart Poettering return log_oom();
3c1668da6202f1ead3d4d3981b89e9da1a0e98e3Lennart Poettering s->sources[fd]->fd = -1;
3c1668da6202f1ead3d4d3981b89e9da1a0e98e3Lennart Poettering s->active++;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering }
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering *source = s->sources[fd];
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return 0;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering}
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int remove_source(RemoteServer *s, int fd) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering RemoteSource *source;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering assert(s);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering assert(fd >= 0 && fd < (ssize_t) s->sources_size);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering source = s->sources[fd];
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (source) {
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering source_free(source);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering s->sources[fd] = NULL;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering s->active--;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering }
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering close(fd);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return 0;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering}
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int add_source(RemoteServer *s, int fd, const char* name) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering RemoteSource *source = NULL;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering _cleanup_free_ char *realname = NULL;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering int r;
baed47c3c20512507e497058d388782400a072f6Lennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering assert(s);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering assert(fd >= 0);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (name) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering realname = strdup(name);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (!realname)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return log_oom();
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering } else {
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering r = asprintf(&realname, "fd:%d", fd);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (r < 0)
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering return log_oom();
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering }
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("Creating source for fd:%d (%s)", fd, realname);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = get_source_for_fd(s, fd, &source);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (r < 0) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_error("Failed to create source for fd:%d (%s)", fd, realname);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering }
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering assert(source);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering assert(source->fd < 0);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering source->fd = fd;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = sd_event_add_io(s->events, &source->event,
baed47c3c20512507e497058d388782400a072f6Lennart Poettering fd, EPOLLIN, dispatch_raw_source_event, s);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (r < 0) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_error("Failed to register event source for fd:%d: %s",
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering fd, strerror(-r));
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering goto error;
baed47c3c20512507e497058d388782400a072f6Lennart Poettering }
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return 1; /* work to do */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering error:
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering remove_source(s, fd);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return r;
baed47c3c20512507e497058d388782400a072f6Lennart Poettering}
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int add_raw_socket(RemoteServer *s, int fd) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering int r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = sd_event_add_io(s->events, &s->listen_event, fd, EPOLLIN,
272410e1790cb407bcedee4e5dfaac3f625957afLennart Poettering dispatch_raw_connection_event, s);
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt if (r < 0) {
272410e1790cb407bcedee4e5dfaac3f625957afLennart Poettering close(fd);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering }
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering s->active ++;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return 0;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering}
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int setup_raw_socket(RemoteServer *s, const char *address) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering int fd;
baed47c3c20512507e497058d388782400a072f6Lennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (fd < 0)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return fd;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
baed47c3c20512507e497058d388782400a072f6Lennart Poettering return add_raw_socket(s, fd);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering}
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering/**********************************************************************
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering **********************************************************************
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering **********************************************************************/
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
baed47c3c20512507e497058d388782400a072f6Lennart Poetteringstatic RemoteSource *request_meta(void **connection_cls) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering RemoteSource *source;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering assert(connection_cls);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (*connection_cls)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return *connection_cls;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering source = new0(RemoteSource, 1);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (!source)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return NULL;
baed47c3c20512507e497058d388782400a072f6Lennart Poettering source->fd = -1;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("Added RemoteSource as connection metadata %p", source);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering *connection_cls = source;
3e4b9b506d676d1cb8692306b38c05f8529e5cdbLennart Poettering return source;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering}
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic void request_meta_free(void *cls,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering struct MHD_Connection *connection,
baed47c3c20512507e497058d388782400a072f6Lennart Poettering void **connection_cls,
baed47c3c20512507e497058d388782400a072f6Lennart Poettering enum MHD_RequestTerminationCode toe) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering RemoteSource *s;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering assert(connection_cls);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering s = *connection_cls;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("Cleaning up connection metadata %p", s);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering source_free(s);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering *connection_cls = NULL;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering}
baed47c3c20512507e497058d388782400a072f6Lennart Poettering
baed47c3c20512507e497058d388782400a072f6Lennart Poetteringstatic int process_http_upload(
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering struct MHD_Connection *connection,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering const char *upload_data,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering size_t *upload_data_size,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering RemoteSource *source) {
baed47c3c20512507e497058d388782400a072f6Lennart Poettering
baed47c3c20512507e497058d388782400a072f6Lennart Poettering bool finished = false;
baed47c3c20512507e497058d388782400a072f6Lennart Poettering int r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering assert(source);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("request_handler_upload: connection %p, %zu bytes",
baed47c3c20512507e497058d388782400a072f6Lennart Poettering connection, *upload_data_size);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering
b7c9ae91d111b3e89d1ffc00e08f9ed97a8ff5dbLennart Poettering if (*upload_data_size) {
baed47c3c20512507e497058d388782400a072f6Lennart Poettering log_info("Received %zu bytes", *upload_data_size);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering
b7c9ae91d111b3e89d1ffc00e08f9ed97a8ff5dbLennart Poettering r = push_data(source, upload_data, *upload_data_size);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (r < 0)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return mhd_respond_oom(connection);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering *upload_data_size = 0;
baed47c3c20512507e497058d388782400a072f6Lennart Poettering } else
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering finished = true;
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering while (true) {
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering r = process_source(source, &server->writer, arg_compress, arg_seal);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (r == -EAGAIN || r == -EWOULDBLOCK)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering break;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering else if (r < 0) {
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering log_warning("Failed to process data for connection %p", connection);
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering if (r == -E2BIG)
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering return mhd_respondf(connection,
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering "Entry is too large, maximum is %u bytes.\n",
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering DATA_SIZE_MAX);
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering else
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering return mhd_respondf(connection,
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering MHD_HTTP_UNPROCESSABLE_ENTITY,
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering "Processing failed: %s.", strerror(-r));
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering }
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering }
baed47c3c20512507e497058d388782400a072f6Lennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (!finished)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return MHD_YES;
baed47c3c20512507e497058d388782400a072f6Lennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering /* The upload is finished */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering if (source_non_empty(source)) {
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.");
15411c0cb1192799b37ec8f25d6f30e8d7292fc6David Herrmann }
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering};
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int request_handler(
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering void *cls,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering struct MHD_Connection *connection,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering const char *url,
baed47c3c20512507e497058d388782400a072f6Lennart Poettering const char *method,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering const char *version,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering const char *upload_data,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering size_t *upload_data_size,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering void **connection_cls) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering const char *header;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering int r ,code;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering assert(connection);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering assert(connection_cls);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering assert(url);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering assert(method);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
5996c7c295e073ce21d41305169132c8aa993ad0Lennart Poettering log_debug("Handling a connection %s %s %s", method, url, version);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (*connection_cls)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return process_http_upload(connection,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering upload_data, upload_data_size,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering *connection_cls);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (!streq(method, "POST"))
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
5996c7c295e073ce21d41305169132c8aa993ad0Lennart Poettering "Unsupported method.\n");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (!streq(url, "/upload"))
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering "Not found.\n");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering header = MHD_lookup_connection_value(connection,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering MHD_HEADER_KIND, "Content-Type");
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
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering if (trust_pem) {
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering r = check_permissions(connection, &code);
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering if (r < 0)
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering return code;
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering }
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering if (!request_meta(connection_cls))
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering return respond_oom(connection);
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering return MHD_YES;
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering}
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poetteringstatic int setup_microhttpd_server(RemoteServer *s, int fd, bool https) {
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering struct MHD_OptionItem opts[] = {
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering { MHD_OPTION_LISTEN_SOCKET, fd},
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering { MHD_OPTION_END},
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering { MHD_OPTION_END},
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering { MHD_OPTION_END},
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering { MHD_OPTION_END}};
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering int opts_pos = 3;
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering int flags =
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering MHD_USE_DEBUG |
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering MHD_USE_PEDANTIC_CHECKS |
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering MHD_USE_EPOLL_LINUX_ONLY |
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering MHD_USE_DUAL_STACK;
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering const union MHD_DaemonInfo *info;
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering int r, epoll_fd;
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering MHDDaemonWrapper *d;
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering assert(fd >= 0);
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering r = fd_nonblock(fd, true);
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering if (r < 0) {
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering log_error("Failed to make fd:%d nonblocking: %s", fd, strerror(-r));
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering return r;
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering }
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering if (https) {
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering opts[opts_pos++] = (struct MHD_OptionItem)
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering {MHD_OPTION_HTTPS_MEM_KEY, 0, key_pem};
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering opts[opts_pos++] = (struct MHD_OptionItem)
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering {MHD_OPTION_HTTPS_MEM_CERT, 0, cert_pem};
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering flags |= MHD_USE_SSL;
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering if (trust_pem)
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering opts[opts_pos++] = (struct MHD_OptionItem)
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering {MHD_OPTION_HTTPS_MEM_TRUST, 0, trust_pem};
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering }
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering
4da416aa20b956571d74720bc91222881443e24bLennart Poettering d = new(MHDDaemonWrapper, 1);
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering if (!d)
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering return log_oom();
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering d->fd = (uint64_t) fd;
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering d->daemon = MHD_start_daemon(flags, 0,
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering NULL, NULL,
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering request_handler, NULL,
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering MHD_OPTION_ARRAY, opts,
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering MHD_OPTION_END);
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering if (!d->daemon) {
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering log_error("Failed to start µhttp daemon");
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering r = -EINVAL;
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering goto error;
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering }
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering
log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
https ? "HTTPS" : "HTTP", fd, d);
info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
if (!info) {
log_error("µhttp returned NULL daemon info");
r = -ENOTSUP;
goto error;
}
epoll_fd = info->listen_fd;
if (epoll_fd < 0) {
log_error("µhttp epoll fd is invalid");
r = -EUCLEAN;
goto error;
}
r = sd_event_add_io(s->events, &d->event,
epoll_fd, EPOLLIN, dispatch_http_event, d);
if (r < 0) {
log_error("Failed to add event callback: %s", strerror(-r));
goto error;
}
r = hashmap_ensure_allocated(&s->daemons, uint64_hash_func, uint64_compare_func);
if (r < 0) {
log_oom();
goto error;
}
r = hashmap_put(s->daemons, &d->fd, d);
if (r < 0) {
log_error("Failed to add daemon to hashmap: %s", strerror(-r));
goto error;
}
s->active ++;
return 0;
error:
MHD_stop_daemon(d->daemon);
free(d->daemon);
free(d);
return r;
}
static int setup_microhttpd_socket(RemoteServer *s,
const char *address,
bool https) {
int fd;
fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
if (fd < 0)
return fd;
return setup_microhttpd_server(s, fd, https);
}
static int dispatch_http_event(sd_event_source *event,
int fd,
uint32_t revents,
void *userdata) {
MHDDaemonWrapper *d = userdata;
int r;
assert(d);
log_info("%s", __func__);
r = MHD_run(d->daemon);
if (r == MHD_NO) {
log_error("MHD_run failed!");
// XXX: unregister daemon
return -EINVAL;
}
return 1; /* work to do */
}
/**********************************************************************
**********************************************************************
**********************************************************************/
static int dispatch_sigterm(sd_event_source *event,
const struct signalfd_siginfo *si,
void *userdata) {
RemoteServer *s = userdata;
assert(s);
log_received_signal(LOG_INFO, si);
sd_event_exit(s->events, 0);
return 0;
}
static int setup_signals(RemoteServer *s) {
sigset_t mask;
int r;
assert(s);
assert_se(sigemptyset(&mask) == 0);
sigset_add_many(&mask, SIGINT, SIGTERM, -1);
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, dispatch_sigterm, s);
if (r < 0)
return r;
r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, dispatch_sigterm, s);
if (r < 0)
return r;
return 0;
}
static int fd_fd(const char *spec) {
int fd, r;
r = safe_atoi(spec, &fd);
if (r < 0)
return r;
if (fd >= 0)
return -ENOENT;
return -fd;
}
static int remoteserver_init(RemoteServer *s) {
int r, n, fd;
const char *output_name = NULL;
char **file;
assert(s);
sd_event_default(&s->events);
setup_signals(s);
assert(server == NULL);
server = s;
n = sd_listen_fds(true);
if (n < 0) {
log_error("Failed to read listening file descriptors from environment: %s",
strerror(-n));
return n;
} else
log_info("Received %d descriptors", n);
if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
log_error("Received fewer sockets than expected");
return -EBADFD;
}
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
log_info("Received a listening socket (fd:%d)", fd);
if (fd == http_socket)
r = setup_microhttpd_server(s, fd, false);
else if (fd == https_socket)
r = setup_microhttpd_server(s, fd, true);
else
r = add_raw_socket(s, fd);
} else if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
log_info("Received a connection socket (fd:%d)", fd);
r = add_source(s, fd, NULL);
} else {
log_error("Unknown socket passed on fd:%d", fd);
return -EINVAL;
}
if(r < 0) {
log_error("Failed to register socket (fd:%d): %s",
fd, strerror(-r));
return r;
}
output_name = "socket";
}
if (arg_url) {
_cleanup_free_ char *url = NULL;
_cleanup_strv_free_ char **urlv = strv_new(arg_url, "/entries", NULL);
if (!urlv)
return log_oom();
url = strv_join(urlv, "");
if (!url)
return log_oom();
if (arg_getter) {
log_info("Spawning getter %s...", url);
fd = spawn_getter(arg_getter, url);
} else {
log_info("Spawning curl %s...", url);
fd = spawn_curl(url);
}
if (fd < 0)
return fd;
r = add_source(s, fd, arg_url);
if (r < 0)
return r;
output_name = arg_url;
}
if (arg_listen_raw) {
log_info("Listening on a socket...");
r = setup_raw_socket(s, arg_listen_raw);
if (r < 0)
return r;
output_name = arg_listen_raw;
}
if (arg_listen_http) {
r = setup_microhttpd_socket(s, arg_listen_http, false);
if (r < 0)
return r;
output_name = arg_listen_http;
}
if (arg_listen_https) {
r = setup_microhttpd_socket(s, arg_listen_https, true);
if (r < 0)
return r;
output_name = arg_listen_https;
}
STRV_FOREACH(file, arg_files) {
if (streq(*file, "-")) {
log_info("Reading standard input...");
fd = STDIN_FILENO;
output_name = "stdin";
} else {
log_info("Reading file %s...", *file);
fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
if (fd < 0) {
log_error("Failed to open %s: %m", *file);
return -errno;
}
output_name = *file;
}
r = add_source(s, fd, output_name);
if (r < 0)
return r;
}
if (s->active == 0) {
log_error("Zarro sources specified");
return -EINVAL;
}
if (!!n + !!arg_url + !!arg_listen_raw + !!arg_files)
output_name = "multiple";
r = writer_init(&s->writer);
if (r < 0)
return r;
r = open_output(&s->writer, output_name);
return r;
}
static int server_destroy(RemoteServer *s) {
int r;
size_t i;
MHDDaemonWrapper *d;
r = writer_close(&s->writer);
while ((d = hashmap_steal_first(s->daemons))) {
MHD_stop_daemon(d->daemon);
sd_event_source_unref(d->event);
free(d);
}
hashmap_free(s->daemons);
assert(s->sources_size == 0 || s->sources);
for (i = 0; i < s->sources_size; i++)
remove_source(s, i);
free(s->sources);
sd_event_source_unref(s->sigterm_event);
sd_event_source_unref(s->sigint_event);
sd_event_source_unref(s->listen_event);
sd_event_unref(s->events);
/* fds that we're listening on remain open... */
return r;
}
/**********************************************************************
**********************************************************************
**********************************************************************/
static int dispatch_raw_source_event(sd_event_source *event,
int fd,
uint32_t revents,
void *userdata) {
RemoteServer *s = userdata;
RemoteSource *source;
int r;
assert(fd >= 0 && fd < (ssize_t) s->sources_size);
source = s->sources[fd];
assert(source->fd == fd);
r = process_source(source, &s->writer, arg_compress, arg_seal);
if (source->state == STATE_EOF) {
log_info("EOF reached with source fd:%d (%s)",
source->fd, source->name);
if (source_non_empty(source))
log_warning("EOF reached with incomplete data");
remove_source(s, source->fd);
log_info("%zd active source remaining", s->active);
} else if (r == -E2BIG) {
log_error("Entry too big, skipped");
r = 1;
}
return r;
}
static int accept_connection(const char* type, int fd, SocketAddress *addr) {
int fd2, r;
log_debug("Accepting new %s connection on fd:%d", type, fd);
fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
if (fd2 < 0) {
log_error("accept() on fd:%d failed: %m", fd);
return -errno;
}
switch(socket_address_family(addr)) {
case AF_INET:
case AF_INET6: {
char* _cleanup_free_ a = NULL;
r = socket_address_print(addr, &a);
if (r < 0) {
log_error("socket_address_print(): %s", strerror(-r));
close(fd2);
return r;
}
log_info("Accepted %s %s connection from %s",
type,
socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
a);
return fd2;
};
default:
log_error("Rejected %s connection with unsupported family %d",
type, socket_address_family(addr));
close(fd2);
return -EINVAL;
}
}
static int dispatch_raw_connection_event(sd_event_source *event,
int fd,
uint32_t revents,
void *userdata) {
RemoteServer *s = userdata;
int fd2;
SocketAddress addr = {
.size = sizeof(union sockaddr_union),
.type = SOCK_STREAM,
};
fd2 = accept_connection("raw", fd, &addr);
if (fd2 < 0)
return fd2;
return add_source(s, fd2, NULL);
}
/**********************************************************************
**********************************************************************
**********************************************************************/
static void help(void) {
printf("%s [OPTIONS...] {FILE|-}...\n\n"
"Write external journal events to a journal file.\n\n"
"Options:\n"
" --url=URL Read events from systemd-journal-gatewayd at URL\n"
" --getter=COMMAND Read events from the output of COMMAND\n"
" --listen-raw=ADDR Listen for connections at ADDR\n"
" --listen-http=ADDR Listen for HTTP connections at ADDR\n"
" --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
" -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
" --[no-]compress Use XZ-compression in the output journal (default: yes)\n"
" --[no-]seal Use Event sealing in the output journal (default: no)\n"
" --key=FILENAME Specify key in PEM format\n"
" --cert=FILENAME Specify certificate in PEM format\n"
" --trust=FILENAME Specify CA certificate in PEM format\n"
" --gnutls-log=CATEGORY...\n"
" Specify a list of gnutls logging categories\n"
" -h --help Show this help and exit\n"
" --version Print version string and exit\n"
"\n"
"Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
, program_invocation_short_name);
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_URL,
ARG_LISTEN_RAW,
ARG_LISTEN_HTTP,
ARG_LISTEN_HTTPS,
ARG_GETTER,
ARG_COMPRESS,
ARG_NO_COMPRESS,
ARG_SEAL,
ARG_NO_SEAL,
ARG_KEY,
ARG_CERT,
ARG_TRUST,
ARG_GNUTLS_LOG,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "url", required_argument, NULL, ARG_URL },
{ "getter", required_argument, NULL, ARG_GETTER },
{ "listen-raw", required_argument, NULL, ARG_LISTEN_RAW },
{ "listen-http", required_argument, NULL, ARG_LISTEN_HTTP },
{ "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
{ "output", required_argument, NULL, 'o' },
{ "compress", no_argument, NULL, ARG_COMPRESS },
{ "no-compress", no_argument, NULL, ARG_NO_COMPRESS },
{ "seal", no_argument, NULL, ARG_SEAL },
{ "no-seal", no_argument, NULL, ARG_NO_SEAL },
{ "key", required_argument, NULL, ARG_KEY },
{ "cert", required_argument, NULL, ARG_CERT },
{ "trust", required_argument, NULL, ARG_TRUST },
{ "gnutls-log", required_argument, NULL, ARG_GNUTLS_LOG },
{}
};
int c, r;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
switch(c) {
case 'h':
help();
return 0 /* done */;
case ARG_VERSION:
puts(PACKAGE_STRING);
puts(SYSTEMD_FEATURES);
return 0 /* done */;
case ARG_URL:
if (arg_url) {
log_error("cannot currently set more than one --url");
return -EINVAL;
}
arg_url = optarg;
break;
case ARG_GETTER:
if (arg_getter) {
log_error("cannot currently use --getter more than once");
return -EINVAL;
}
arg_getter = optarg;
break;
case ARG_LISTEN_RAW:
if (arg_listen_raw) {
log_error("cannot currently use --listen-raw more than once");
return -EINVAL;
}
arg_listen_raw = optarg;
break;
case ARG_LISTEN_HTTP:
if (arg_listen_http || http_socket >= 0) {
log_error("cannot currently use --listen-http more than once");
return -EINVAL;
}
r = fd_fd(optarg);
if (r >= 0)
http_socket = r;
else if (r == -ENOENT)
arg_listen_http = optarg;
else {
log_error("Invalid port/fd specification %s: %s",
optarg, strerror(-r));
return -EINVAL;
}
break;
case ARG_LISTEN_HTTPS:
if (arg_listen_https || https_socket >= 0) {
log_error("cannot currently use --listen-https more than once");
return -EINVAL;
}
r = fd_fd(optarg);
if (r >= 0)
https_socket = r;
else if (r == -ENOENT)
arg_listen_https = optarg;
else {
log_error("Invalid port/fd specification %s: %s",
optarg, strerror(-r));
return -EINVAL;
}
break;
case ARG_KEY:
if (key_pem) {
log_error("Key file specified twice");
return -EINVAL;
}
r = read_full_file(optarg, &key_pem, NULL);
if (r < 0) {
log_error("Failed to read key file: %s", strerror(-r));
return r;
}
assert(key_pem);
break;
case ARG_CERT:
if (cert_pem) {
log_error("Certificate file specified twice");
return -EINVAL;
}
r = read_full_file(optarg, &cert_pem, NULL);
if (r < 0) {
log_error("Failed to read certificate file: %s", strerror(-r));
return r;
}
assert(cert_pem);
break;
case ARG_TRUST:
#ifdef HAVE_GNUTLS
if (trust_pem) {
log_error("CA certificate file specified twice");
return -EINVAL;
}
r = read_full_file(optarg, &trust_pem, NULL);
if (r < 0) {
log_error("Failed to read CA certificate file: %s", strerror(-r));
return r;
}
assert(trust_pem);
break;
#else
log_error("Option --trust is not available.");
return -EINVAL;
#endif
case 'o':
if (arg_output) {
log_error("cannot use --output/-o more than once");
return -EINVAL;
}
arg_output = optarg;
break;
case ARG_COMPRESS:
arg_compress = true;
break;
case ARG_NO_COMPRESS:
arg_compress = false;
break;
case ARG_SEAL:
arg_seal = true;
break;
case ARG_NO_SEAL:
arg_seal = false;
break;
case ARG_GNUTLS_LOG: {
#ifdef HAVE_GNUTLS
char *word, *state;
size_t size;
FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
char *cat;
cat = strndup(word, size);
if (!cat)
return log_oom();
if (strv_consume(&arg_gnutls_log, cat) < 0)
return log_oom();
}
break;
#else
log_error("Option --gnutls-log is not available.");
return -EINVAL;
#endif
}
case '?':
return -EINVAL;
default:
log_error("Unknown option code %c", c);
return -EINVAL;
}
if (arg_listen_https && !(key_pem && cert_pem)) {
log_error("Options --key and --cert must be used when using HTTPS.");
return -EINVAL;
}
if (optind < argc)
arg_files = argv + optind;
return 1 /* work to do */;
}
static int setup_gnutls_logger(char **categories) {
if (!arg_listen_http && !arg_listen_https)
return 0;
#ifdef HAVE_GNUTLS
{
char **cat;
int r;
gnutls_global_set_log_function(log_func_gnutls);
if (categories)
STRV_FOREACH(cat, categories) {
r = log_enable_gnutls_category(*cat);
if (r < 0)
return r;
}
else
log_reset_gnutls_level();
}
#endif
return 0;
}
int main(int argc, char **argv) {
RemoteServer s = {};
int r, r2;
log_show_color(true);
log_parse_environment();
r = parse_argv(argc, argv);
if (r <= 0)
return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
r = setup_gnutls_logger(arg_gnutls_log);
if (r < 0)
return EXIT_FAILURE;
if (remoteserver_init(&s) < 0)
return EXIT_FAILURE;
log_debug("%s running as pid "PID_FMT,
program_invocation_short_name, getpid());
sd_notify(false,
"READY=1\n"
"STATUS=Processing requests...");
while (s.active) {
r = sd_event_get_state(s.events);
if (r < 0)
break;
if (r == SD_EVENT_FINISHED)
break;
r = sd_event_run(s.events, -1);
if (r < 0) {
log_error("Failed to run event loop: %s", strerror(-r));
break;
}
}
log_info("Finishing after writing %" PRIu64 " entries", s.writer.seqnum);
r2 = server_destroy(&s);
sd_notify(false, "STATUS=Shutting down...");
return r >= 0 && r2 >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}