journal-remote.c revision 7a855149eaf6dbd336d9defab5b4a9c70b75d5e6
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen/***
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen This file is part of systemd.
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen Copyright 2012 Zbigniew Jędrzejewski-Szmek
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen systemd is free software; you can redistribute it and/or modify it
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen under the terms of the GNU Lesser General Public License as published by
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen (at your option) any later version.
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen systemd is distributed in the hope that it will be useful, but
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen Lesser General Public License for more details.
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen You should have received a copy of the GNU Lesser General Public License
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen***/
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen#include <errno.h>
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen#include <fcntl.h>
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen#include <stdio.h>
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen#include <stdlib.h>
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen#include <string.h>
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen#include <sys/prctl.h>
a501033335ed402c8f7e86fe41a15531ba69abd7Tom Gundersen#include <sys/socket.h>
a501033335ed402c8f7e86fe41a15531ba69abd7Tom Gundersen#include <sys/stat.h>
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen#include <sys/types.h>
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen#include <unistd.h>
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen#include <getopt.h>
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen#include "sd-daemon.h"
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen#include "journal-file.h"
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen#include "journald-native.h"
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen#include "socket-util.h"
daeb71a36a98834664e4d95773a3629b746f4db8Tom Gundersen#include "mkdir.h"
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen#include "build.h"
3aeb37bc4f32b5edc334f2ac7c5d3c7b0a121328Tom Gundersen#include "macro.h"
c6f7c917a1b494d4455800823472227463f87438Tom Gundersen#include "strv.h"
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering#include "fileio.h"
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen#include "conf-parser.h"
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen#include "siphash24.h"
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen#ifdef HAVE_GNUTLS
a501033335ed402c8f7e86fe41a15531ba69abd7Tom Gundersen#include <gnutls/gnutls.h>
a501033335ed402c8f7e86fe41a15531ba69abd7Tom Gundersen#endif
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen#include "journal-remote.h"
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen#include "journal-remote-write.h"
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen
97f2d76d4f4dfab8b0629c09926a05a1e5621125Tom Gundersen#define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen#define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek#define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek#define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmekstatic char* arg_url = NULL;
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmekstatic char* arg_getter = NULL;
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmekstatic char* arg_listen_raw = NULL;
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmekstatic char* arg_listen_http = NULL;
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmekstatic char* arg_listen_https = NULL;
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmekstatic char** arg_files = NULL;
5b9d4dc05560ddda89e48b6b39365824b15e1300Tom Gundersenstatic int arg_compress = true;
5b9d4dc05560ddda89e48b6b39365824b15e1300Tom Gundersenstatic int arg_seal = false;
5b9d4dc05560ddda89e48b6b39365824b15e1300Tom Gundersenstatic int http_socket = -1, https_socket = -1;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic char** arg_gnutls_log = NULL;
5b9d4dc05560ddda89e48b6b39365824b15e1300Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic JournalWriteSplitMode arg_split_mode = JOURNAL_WRITE_SPLIT_HOST;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic char* arg_output = NULL;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic char *arg_key = NULL;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic char *arg_cert = NULL;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic char *arg_trust = NULL;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic bool arg_trust_all = false;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen/**********************************************************************
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen **********************************************************************
977085794d2996320e345433403de75f662b0622Tom Gundersen **********************************************************************/
977085794d2996320e345433403de75f662b0622Tom Gundersen
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersenstatic int spawn_child(const char* child, char** argv) {
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen int fd[2];
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen pid_t parent_pid, child_pid;
5b9d4dc05560ddda89e48b6b39365824b15e1300Tom Gundersen int r;
5b9d4dc05560ddda89e48b6b39365824b15e1300Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (pipe(fd) < 0) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen log_error("Failed to create pager pipe: %m");
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen return -errno;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen }
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen parent_pid = getpid();
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen child_pid = fork();
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (child_pid < 0) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen r = -errno;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen log_error("Failed to fork: %m");
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen safe_close_pair(fd);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen return r;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen }
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
d2df0d0ed3a88e491405b403e6022e6619750130Tom Gundersen /* In the child */
edf029b7fd9a5853a87d3ca99aac2922bb8a277eTom Gundersen if (child_pid == 0) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen r = dup2(fd[1], STDOUT_FILENO);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (r < 0) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen log_error("Failed to dup pipe to stdout: %m");
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen _exit(EXIT_FAILURE);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen }
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen safe_close_pair(fd);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen /* Make sure the child goes away when the parent dies */
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen _exit(EXIT_FAILURE);
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen /* Check whether our parent died before we were able
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen * to set the death signal */
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (getppid() != parent_pid)
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen _exit(EXIT_SUCCESS);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen execvp(child, argv);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen log_error("Failed to exec child %s: %m", child);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen _exit(EXIT_FAILURE);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen }
ecb08ec6a5c52f2d940f3b8147e2a480affd46e1Zbigniew Jędrzejewski-Szmek
6e37cd2f4af8928d905203108a4331e375d7127cThomas Hindoe Paaboel Andersen r = close(fd[1]);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (r < 0)
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen log_warning("Failed to close write end of pipe: %m");
187dc6e554f2d5b4b5a3bee72c73ff5df6418aa6Thomas Hindoe Paaboel Andersen
187dc6e554f2d5b4b5a3bee72c73ff5df6418aa6Thomas Hindoe Paaboel Andersen return fd[0];
187dc6e554f2d5b4b5a3bee72c73ff5df6418aa6Thomas Hindoe Paaboel Andersen}
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic int spawn_curl(const char* url) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen char **argv = STRV_MAKE("curl",
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen "-HAccept: application/vnd.fdo.journal",
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen "--silent",
ecb08ec6a5c52f2d940f3b8147e2a480affd46e1Zbigniew Jędrzejewski-Szmek "--show-error",
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen url);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen int r;
ed88bcfb7c15029f9fc95ee2380759a9eb782d46Zbigniew Jędrzejewski-Szmek
ed88bcfb7c15029f9fc95ee2380759a9eb782d46Zbigniew Jędrzejewski-Szmek r = spawn_child("curl", argv);
ed88bcfb7c15029f9fc95ee2380759a9eb782d46Zbigniew Jędrzejewski-Szmek if (r < 0)
ed88bcfb7c15029f9fc95ee2380759a9eb782d46Zbigniew Jędrzejewski-Szmek log_error("Failed to spawn curl: %m");
ed88bcfb7c15029f9fc95ee2380759a9eb782d46Zbigniew Jędrzejewski-Szmek return r;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen}
ecb08ec6a5c52f2d940f3b8147e2a480affd46e1Zbigniew Jędrzejewski-Szmek
ecb08ec6a5c52f2d940f3b8147e2a480affd46e1Zbigniew Jędrzejewski-Szmekstatic int spawn_getter(const char *getter, const char *url) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen int r;
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen _cleanup_strv_free_ char **words = NULL;
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen assert(getter);
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen r = strv_split_quoted(&words, getter);
e9f3d2d508bfd9fb5b54e82994bda365a71eb864Zbigniew Jędrzejewski-Szmek if (r < 0) {
e9f3d2d508bfd9fb5b54e82994bda365a71eb864Zbigniew Jędrzejewski-Szmek log_error("Failed to split getter option: %s", strerror(-r));
e9f3d2d508bfd9fb5b54e82994bda365a71eb864Zbigniew Jędrzejewski-Szmek return r;
36f822c4bd077f9121757e24b6516e5c7ada63b5Zbigniew Jędrzejewski-Szmek }
36f822c4bd077f9121757e24b6516e5c7ada63b5Zbigniew Jędrzejewski-Szmek
ecb08ec6a5c52f2d940f3b8147e2a480affd46e1Zbigniew Jędrzejewski-Szmek r = strv_extend(&words, url);
36f822c4bd077f9121757e24b6516e5c7ada63b5Zbigniew Jędrzejewski-Szmek if (r < 0) {
98a375f6d5cac24eb80d6d4e00699851324afdecTom Gundersen log_error("Failed to create command line: %s", strerror(-r));
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen return r;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen }
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen r = spawn_child(words[0], words);
ecb08ec6a5c52f2d940f3b8147e2a480affd46e1Zbigniew Jędrzejewski-Szmek if (r < 0)
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen log_error("Failed to spawn getter %s: %m", getter);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen return r;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen}
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen
f8a0bb5285024b6ce372c3157e761e6543ebdcd2Andreas Henriksson#define filename_escape(s) xescape((s), "/ ")
a2a5291b3f5ab6ed4c92f51d0fd10a03047380d8Zbigniew Jędrzejewski-Szmek
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersenstatic int open_output(Writer *w, const char* host) {
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen _cleanup_free_ char *_output = NULL;
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen const char *output;
74df0fca09b3c31ed19e14ba80f996fdff772417Lennart Poettering int r;
b5884878a2874447b2a9f07f324a7cd909d96d48Lennart Poettering
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt switch (arg_split_mode) {
74df0fca09b3c31ed19e14ba80f996fdff772417Lennart Poettering case JOURNAL_WRITE_SPLIT_NONE:
b5884878a2874447b2a9f07f324a7cd909d96d48Lennart Poettering output = arg_output ?: REMOTE_JOURNAL_PATH "/remote.journal";
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen break;
a2a5291b3f5ab6ed4c92f51d0fd10a03047380d8Zbigniew Jędrzejewski-Szmek
a2a5291b3f5ab6ed4c92f51d0fd10a03047380d8Zbigniew Jędrzejewski-Szmek case JOURNAL_WRITE_SPLIT_HOST: {
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen _cleanup_free_ char *name;
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen assert(host);
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen name = filename_escape(host);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (!name)
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen return log_oom();
edf029b7fd9a5853a87d3ca99aac2922bb8a277eTom Gundersen
edf029b7fd9a5853a87d3ca99aac2922bb8a277eTom Gundersen r = asprintf(&_output, "%s/remote-%s.journal",
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen arg_output ?: REMOTE_JOURNAL_PATH,
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen name);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (r < 0)
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen return log_oom();
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen
3f85ef0f05ffc51e19f86fb83a1c51e8e3cd6817Harald Hoyer output = _output;
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen break;
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen }
97f2d76d4f4dfab8b0629c09926a05a1e5621125Tom Gundersen
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek default:
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen assert_not_reached("what?");
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek }
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt r = journal_file_open_reliably(output,
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen O_RDWR|O_CREAT, 0640,
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen arg_compress, arg_seal,
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen &w->metrics,
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen w->mmap,
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen NULL, &w->journal);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (r < 0)
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen log_error("Failed to open output journal %s: %s",
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen output, strerror(-r));
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen else
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen log_info("Opened output file %s", w->journal->path);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen return r;
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek}
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen/**********************************************************************
464cf22f17e0cf2d8bfa6d72b5e7a662d634f149Tom Gundersen **********************************************************************
464cf22f17e0cf2d8bfa6d72b5e7a662d634f149Tom Gundersen **********************************************************************/
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic int init_writer_hashmap(RemoteServer *s) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen static const struct {
eb7040ec50fbfe5aad9eaf305bd442a4a235abaaTom Gundersen hash_func_t hash_func;
b3e013148603aa670bc2c060ac63d48e54d76fc2Tom Gundersen compare_func_t compare_func;
edbb03e95a3c31bf719d5c6c46eec14d0bcb9c8fTom Gundersen } functions[] = {
edbb03e95a3c31bf719d5c6c46eec14d0bcb9c8fTom Gundersen [JOURNAL_WRITE_SPLIT_NONE] = {trivial_hash_func,
edbb03e95a3c31bf719d5c6c46eec14d0bcb9c8fTom Gundersen trivial_compare_func},
eb7040ec50fbfe5aad9eaf305bd442a4a235abaaTom Gundersen [JOURNAL_WRITE_SPLIT_HOST] = {string_hash_func,
b3e013148603aa670bc2c060ac63d48e54d76fc2Tom Gundersen string_compare_func},
9b1c2626cef16722603bded9bb52033aba34dd74Tom Gundersen };
bf175aafd20c9ef974709ef12c5acf836121af33Tom Gundersen
b3e013148603aa670bc2c060ac63d48e54d76fc2Tom Gundersen assert(arg_split_mode >= 0 && arg_split_mode < (int) ELEMENTSOF(functions));
b3e013148603aa670bc2c060ac63d48e54d76fc2Tom Gundersen
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen s->writers = hashmap_new(functions[arg_split_mode].hash_func,
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen functions[arg_split_mode].compare_func);
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen if (!s->writers)
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen return log_oom();
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen return 0;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen}
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersenstatic int get_writer(RemoteServer *s, const char *host,
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen Writer **writer) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen const void *key;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen _cleanup_writer_unref_ Writer *w = NULL;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen int r;
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen switch(arg_split_mode) {
f1ac700248f231b7bdac2aafe8c35650efddb89fTom Gundersen case JOURNAL_WRITE_SPLIT_NONE:
f1ac700248f231b7bdac2aafe8c35650efddb89fTom Gundersen key = "one and only";
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen break;
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersen
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen case JOURNAL_WRITE_SPLIT_HOST:
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen assert(host);
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersen key = host;
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersen break;
f1ac700248f231b7bdac2aafe8c35650efddb89fTom Gundersen
f1ac700248f231b7bdac2aafe8c35650efddb89fTom Gundersen default:
f1ac700248f231b7bdac2aafe8c35650efddb89fTom Gundersen assert_not_reached("what split mode?");
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen }
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen w = hashmap_get(s->writers, key);
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen if (w)
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen writer_ref(w);
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen else {
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen w = writer_new(s);
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen if (!w)
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen return log_oom();
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersen
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST) {
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen w->hashmap_key = strdup(key);
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersen if (!w->hashmap_key)
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersen return log_oom();
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen }
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen r = open_output(w, host);
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen if (r < 0)
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen return r;
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen r = hashmap_put(s->writers, w->hashmap_key ?: key, w);
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersen if (r < 0)
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersen return r;
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen }
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersen
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen *writer = w;
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersen w = NULL;
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen return 0;
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen}
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersen/**********************************************************************
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersen **********************************************************************
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen **********************************************************************/
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen/* This should go away as soon as µhttpd allows state to be passed around. */
464cf22f17e0cf2d8bfa6d72b5e7a662d634f149Tom Gundersenstatic RemoteServer *server;
464cf22f17e0cf2d8bfa6d72b5e7a662d634f149Tom Gundersen
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poetteringstatic int dispatch_raw_source_event(sd_event_source *event,
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen int fd,
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen uint32_t revents,
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering void *userdata);
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersenstatic int dispatch_raw_connection_event(sd_event_source *event,
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering int fd,
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering uint32_t revents,
b5db00e52ee2e20578839e4e4488f7b9af9abc38Umut Tezduyar Lindskog void *userdata);
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersenstatic int dispatch_http_event(sd_event_source *event,
55428d84f31b52da1c50b7469f14e15740547f20Tom Gundersen int fd,
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen uint32_t revents,
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering void *userdata);
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersenstatic int get_source_for_fd(RemoteServer *s,
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen int fd, char *name, RemoteSource **source) {
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen Writer *writer;
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersen int r;
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersen
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen assert(fd >= 0);
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen assert(source);
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
464cf22f17e0cf2d8bfa6d72b5e7a662d634f149Tom Gundersen return log_oom();
464cf22f17e0cf2d8bfa6d72b5e7a662d634f149Tom Gundersen
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen r = get_writer(s, name, &writer);
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen if (r < 0) {
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen log_warning("Failed to get writer for source %s: %s",
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen name, strerror(-r));
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen return r;
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen }
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen if (s->sources[fd] == NULL) {
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen s->sources[fd] = source_new(fd, false, name, writer);
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen if (!s->sources[fd]) {
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen writer_unref(writer);
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen return log_oom();
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen }
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen s->active++;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen }
aedca89268ed4fd6be41e55a605f011033ad1fb5Tom Gundersen
464cf22f17e0cf2d8bfa6d72b5e7a662d634f149Tom Gundersen *source = s->sources[fd];
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen return 0;
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poettering}
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poettering
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poetteringstatic int remove_source(RemoteServer *s, int fd) {
a501033335ed402c8f7e86fe41a15531ba69abd7Tom Gundersen RemoteSource *source;
aedca89268ed4fd6be41e55a605f011033ad1fb5Tom Gundersen
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen assert(s);
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poettering assert(fd >= 0 && fd < (ssize_t) s->sources_size);
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poettering
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen source = s->sources[fd];
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen if (source) {
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen /* this closes fd too */
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen source_free(source);
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen s->sources[fd] = NULL;
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen s->active--;
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen }
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen return 0;
daeb71a36a98834664e4d95773a3629b746f4db8Tom Gundersen}
68ba38770640413b4fa06773447666eb88a38d4cTom Gundersen
68ba38770640413b4fa06773447666eb88a38d4cTom Gundersenstatic int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen RemoteSource *source;
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen int r;
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen
e51660ae56bb747ece2cab8fe6eec37f4d06a438Tom Gundersen assert(s);
e51660ae56bb747ece2cab8fe6eec37f4d06a438Tom Gundersen assert(fd >= 0);
e51660ae56bb747ece2cab8fe6eec37f4d06a438Tom Gundersen assert(name);
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen if (!own_name) {
daeb71a36a98834664e4d95773a3629b746f4db8Tom Gundersen name = strdup(name);
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen if (!name)
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen return log_oom();
daeb71a36a98834664e4d95773a3629b746f4db8Tom Gundersen }
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen r = get_source_for_fd(s, fd, name, &source);
daeb71a36a98834664e4d95773a3629b746f4db8Tom Gundersen if (r < 0) {
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen log_error("Failed to create source for fd:%d (%s): %s",
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen fd, name, strerror(-r));
daeb71a36a98834664e4d95773a3629b746f4db8Tom Gundersen return r;
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen }
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen r = sd_event_add_io(s->events, &source->event,
daeb71a36a98834664e4d95773a3629b746f4db8Tom Gundersen fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
daeb71a36a98834664e4d95773a3629b746f4db8Tom Gundersen dispatch_raw_source_event, s);
daeb71a36a98834664e4d95773a3629b746f4db8Tom Gundersen if (r < 0) {
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen log_error("Failed to register event source for fd:%d: %s",
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersen fd, strerror(-r));
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen goto error;
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen }
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen return 1; /* work to do */
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen error:
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen remove_source(s, fd);
92d927f850d4b668b44f3e5f41e266d934d03726Tom Gundersen return r;
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen}
a669ea9860900d5cdebbc4cb9aaea72db7e28a02Tom Gundersen
a669ea9860900d5cdebbc4cb9aaea72db7e28a02Tom Gundersenstatic int add_raw_socket(RemoteServer *s, int fd) {
a669ea9860900d5cdebbc4cb9aaea72db7e28a02Tom Gundersen int r;
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen r = sd_event_add_io(s->events, &s->listen_event,
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen fd, EPOLLIN,
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen dispatch_raw_connection_event, s);
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen if (r < 0) {
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen close(fd);
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen return r;
a669ea9860900d5cdebbc4cb9aaea72db7e28a02Tom Gundersen }
a669ea9860900d5cdebbc4cb9aaea72db7e28a02Tom Gundersen
a669ea9860900d5cdebbc4cb9aaea72db7e28a02Tom Gundersen s->active ++;
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen return 0;
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen}
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersenstatic int setup_raw_socket(RemoteServer *s, const char *address) {
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen int fd;
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen if (fd < 0)
aedca89268ed4fd6be41e55a605f011033ad1fb5Tom Gundersen return fd;
464cf22f17e0cf2d8bfa6d72b5e7a662d634f149Tom Gundersen
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt return add_raw_socket(s, fd);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt}
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen
d95b83b87d7d7c50e550f7128827f73a321c8934Tom Gundersen/**********************************************************************
d95b83b87d7d7c50e550f7128827f73a321c8934Tom Gundersen **********************************************************************
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen **********************************************************************/
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersenstatic RemoteSource *request_meta(void **connection_cls, int fd, char *hostname) {
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen RemoteSource *source;
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen Writer *writer;
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen int r;
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen assert(connection_cls);
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen if (*connection_cls)
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen return *connection_cls;
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen r = get_writer(server, hostname, &writer);
aedca89268ed4fd6be41e55a605f011033ad1fb5Tom Gundersen if (r < 0) {
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen log_warning("Failed to get writer for source %s: %s",
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen hostname, strerror(-r));
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen return NULL;
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen }
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen source = source_new(fd, true, hostname, writer);
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen if (!source) {
2c5859afecee81e345fc9526b1083bf79990ffb8Daniel Mack log_oom();
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen writer_unref(writer);
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen return NULL;
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen }
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen log_debug("Added RemoteSource as connection metadata %p", source);
464cf22f17e0cf2d8bfa6d72b5e7a662d634f149Tom Gundersen
464cf22f17e0cf2d8bfa6d72b5e7a662d634f149Tom Gundersen *connection_cls = source;
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen return source;
2c5859afecee81e345fc9526b1083bf79990ffb8Daniel Mack}
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen
e51660ae56bb747ece2cab8fe6eec37f4d06a438Tom Gundersenstatic void request_meta_free(void *cls,
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen struct MHD_Connection *connection,
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen void **connection_cls,
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen enum MHD_RequestTerminationCode toe) {
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen RemoteSource *s;
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen assert(connection_cls);
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen s = *connection_cls;
464cf22f17e0cf2d8bfa6d72b5e7a662d634f149Tom Gundersen
464cf22f17e0cf2d8bfa6d72b5e7a662d634f149Tom Gundersen log_debug("Cleaning up connection metadata %p", s);
464cf22f17e0cf2d8bfa6d72b5e7a662d634f149Tom Gundersen source_free(s);
*connection_cls = NULL;
}
static int process_http_upload(
struct MHD_Connection *connection,
const char *upload_data,
size_t *upload_data_size,
RemoteSource *source) {
bool finished = false;
size_t remaining;
int r;
assert(source);
log_debug("request_handler_upload: connection %p, %zu bytes",
connection, *upload_data_size);
if (*upload_data_size) {
log_debug("Received %zu bytes", *upload_data_size);
r = push_data(source, upload_data, *upload_data_size);
if (r < 0)
return mhd_respond_oom(connection);
*upload_data_size = 0;
} else
finished = true;
while (true) {
r = process_source(source, arg_compress, arg_seal);
if (r == -EAGAIN || r == -EWOULDBLOCK)
break;
else if (r < 0) {
log_warning("Failed to process data for connection %p", connection);
if (r == -E2BIG)
return mhd_respondf(connection,
MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
"Entry is too large, maximum is %u bytes.\n",
DATA_SIZE_MAX);
else
return mhd_respondf(connection,
MHD_HTTP_UNPROCESSABLE_ENTITY,
"Processing failed: %s.", strerror(-r));
}
}
if (!finished)
return MHD_YES;
/* The upload is finished */
remaining = source_non_empty(source);
if (remaining > 0) {
log_warning("Premature EOFbyte. %zu bytes lost.", remaining);
return mhd_respondf(connection, MHD_HTTP_EXPECTATION_FAILED,
"Premature EOF. %zu bytes of trailing data not processed.",
remaining);
}
return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
};
static int request_handler(
void *cls,
struct MHD_Connection *connection,
const char *url,
const char *method,
const char *version,
const char *upload_data,
size_t *upload_data_size,
void **connection_cls) {
const char *header;
int r, code, fd;
_cleanup_free_ char *hostname = NULL;
assert(connection);
assert(connection_cls);
assert(url);
assert(method);
log_debug("Handling a connection %s %s %s", method, url, version);
if (*connection_cls)
return process_http_upload(connection,
upload_data, upload_data_size,
*connection_cls);
if (!streq(method, "POST"))
return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
"Unsupported method.\n");
if (!streq(url, "/upload"))
return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
"Not found.\n");
header = MHD_lookup_connection_value(connection,
MHD_HEADER_KIND, "Content-Type");
if (!header || !streq(header, "application/vnd.fdo.journal"))
return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
"Content-Type: application/vnd.fdo.journal"
" is required.\n");
{
const union MHD_ConnectionInfo *ci;
ci = MHD_get_connection_info(connection,
MHD_CONNECTION_INFO_CONNECTION_FD);
if (!ci) {
log_error("MHD_get_connection_info failed: cannot get remote fd");
return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
"Cannot check remote address");
}
fd = ci->connect_fd;
assert(fd >= 0);
}
if (server->check_trust) {
r = check_permissions(connection, &code, &hostname);
if (r < 0)
return code;
} else {
r = getnameinfo_pretty(fd, &hostname);
if (r < 0) {
return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
"Cannot check remote hostname");
}
}
assert(hostname);
if (!request_meta(connection_cls, fd, hostname))
return respond_oom(connection);
hostname = NULL;
return MHD_YES;
}
static int setup_microhttpd_server(RemoteServer *s,
int fd,
const char *key,
const char *cert,
const char *trust) {
struct MHD_OptionItem opts[] = {
{ MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
{ MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
{ MHD_OPTION_LISTEN_SOCKET, fd},
{ MHD_OPTION_END},
{ MHD_OPTION_END},
{ MHD_OPTION_END},
{ MHD_OPTION_END}};
int opts_pos = 3;
int flags =
MHD_USE_DEBUG |
MHD_USE_PEDANTIC_CHECKS |
MHD_USE_EPOLL_LINUX_ONLY |
MHD_USE_DUAL_STACK;
const union MHD_DaemonInfo *info;
int r, epoll_fd;
MHDDaemonWrapper *d;
assert(fd >= 0);
r = fd_nonblock(fd, true);
if (r < 0) {
log_error("Failed to make fd:%d nonblocking: %s", fd, strerror(-r));
return r;
}
if (key) {
assert(cert);
opts[opts_pos++] = (struct MHD_OptionItem)
{MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
opts[opts_pos++] = (struct MHD_OptionItem)
{MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
flags |= MHD_USE_SSL;
if (trust)
opts[opts_pos++] = (struct MHD_OptionItem)
{MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
}
d = new(MHDDaemonWrapper, 1);
if (!d)
return log_oom();
d->fd = (uint64_t) fd;
d->daemon = MHD_start_daemon(flags, 0,
NULL, NULL,
request_handler, NULL,
MHD_OPTION_ARRAY, opts,
MHD_OPTION_END);
if (!d->daemon) {
log_error("Failed to start µhttp daemon");
r = -EINVAL;
goto error;
}
log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
key ? "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,
const char *key,
const char *cert,
const char *trust) {
int fd;
fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
if (fd < 0)
return fd;
return setup_microhttpd_server(s, fd, key, cert, trust);
}
static int dispatch_http_event(sd_event_source *event,
int fd,
uint32_t revents,
void *userdata) {
MHDDaemonWrapper *d = userdata;
int r;
assert(d);
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 -EINVAL;
return fd;
}
static int remoteserver_init(RemoteServer *s,
const char* key,
const char* cert,
const char* trust) {
int r, n, fd;
char **file;
assert(s);
if ((arg_listen_raw || arg_listen_http) && trust) {
log_error("Option --trust makes all non-HTTPS connections untrusted.");
return -EINVAL;
}
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, NULL, NULL, NULL);
else if (fd == https_socket)
r = setup_microhttpd_server(s, fd, key, cert, trust);
else
r = add_raw_socket(s, fd);
} else if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
char *hostname;
r = getnameinfo_pretty(fd, &hostname);
if (r < 0) {
log_error("Failed to retrieve remote name: %s", strerror(-r));
return r;
}
log_info("Received a connection socket (fd:%d) from %s", fd, hostname);
r = add_source(s, fd, hostname, true);
if (r < 0)
free(hostname);
} 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;
}
}
if (arg_url) {
const char *url, *hostname;
url = strappenda(arg_url, "/entries");
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;
hostname =
startswith(arg_url, "https://") ?:
startswith(arg_url, "http://") ?:
arg_url;
r = add_source(s, fd, (char*) hostname, false);
if (r < 0)
return r;
}
if (arg_listen_raw) {
log_info("Listening on a socket...");
r = setup_raw_socket(s, arg_listen_raw);
if (r < 0)
return r;
}
if (arg_listen_http) {
r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
if (r < 0)
return r;
}
if (arg_listen_https) {
r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
if (r < 0)
return r;
}
STRV_FOREACH(file, arg_files) {
const char *output_name;
if (streq(*file, "-")) {
log_info("Using standard input as source.");
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, (char*) output_name, false);
if (r < 0)
return r;
}
if (s->active == 0) {
log_error("Zarro sources specified");
return -EINVAL;
}
r = init_writer_hashmap(s);
if (r < 0)
return r;
if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) {
/* In this case we know what the writer will be
called, so we can create it and verify that we can
create output as expected. */
r = get_writer(s, NULL, &s->_single_writer);
if (r < 0)
return r;
}
return 0;
}
static void server_destroy(RemoteServer *s) {
size_t i;
MHDDaemonWrapper *d;
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);
writer_unref(s->_single_writer);
hashmap_free(s->writers);
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... */
}
/**********************************************************************
**********************************************************************
**********************************************************************/
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, arg_compress, arg_seal);
if (source->state == STATE_EOF) {
size_t remaining;
log_info("EOF reached with source fd:%d (%s)",
source->fd, source->name);
remaining = source_non_empty(source);
if (remaining > 0)
log_warning("Premature EOF. %zu bytes lost.", remaining);
remove_source(s, source->fd);
log_info("%zd active sources remaining", s->active);
return 0;
} else if (r == -E2BIG) {
log_error("Entry too big, skipped");
return 1;
} else if (r == -EAGAIN) {
return 0;
} else if (r < 0) {
log_info("Closing connection: %s", strerror(-r));
remove_source(server, fd);
return 0;
} else
return 1;
}
static int accept_connection(const char* type, int fd,
SocketAddress *addr, char **hostname) {
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: {
_cleanup_free_ char *a = NULL;
char *b;
r = socket_address_print(addr, &a);
if (r < 0) {
log_error("socket_address_print(): %s", strerror(-r));
close(fd2);
return r;
}
r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
if (r < 0) {
close(fd2);
return r;
}
log_info("Accepted %s %s connection from %s",
type,
socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
a);
*hostname = b;
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, r;
SocketAddress addr = {
.size = sizeof(union sockaddr_union),
.type = SOCK_STREAM,
};
char *hostname;
fd2 = accept_connection("raw", fd, &addr, &hostname);
if (fd2 < 0)
return fd2;
r = add_source(s, fd2, hostname, true);
if (r < 0)
free(hostname);
return r;
}
/**********************************************************************
**********************************************************************
**********************************************************************/
static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
[JOURNAL_WRITE_SPLIT_NONE] = "none",
[JOURNAL_WRITE_SPLIT_HOST] = "host",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
journal_write_split_mode,
JournalWriteSplitMode,
"Failed to parse split mode setting");
static int parse_config(void) {
const ConfigTableItem items[] = {
{ "Remote", "SplitMode", config_parse_write_split_mode, 0, &arg_split_mode },
{ "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key },
{ "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert },
{ "Remote", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
{}};
return config_parse(NULL, PKGSYSCONFDIR "/journal-remote.conf", NULL,
"Remote\0",
config_item_table_lookup, items,
false, false, true, NULL);
}
static void help(void) {
printf("%s [OPTIONS...] {FILE|-}...\n\n"
"Write external journal events to journal file(s).\n\n"
" -h --help Show this help\n"
" --version Show package version\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"
" --compress[=BOOL] Use XZ-compression in the output journal (default: yes)\n"
" --seal[=BOOL] Use Event sealing in the output journal (default: no)\n"
" --key=FILENAME Specify key in PEM format (default:\n"
" \"" PRIV_KEY_FILE "\")\n"
" --cert=FILENAME Specify certificate in PEM format (default:\n"
" \"" CERT_FILE "\")\n"
" --trust=FILENAME|all Specify CA certificate or disable checking (default:\n"
" \"" TRUST_FILE "\")\n"
" --gnutls-log=CATEGORY...\n"
" Specify a list of gnutls logging categories\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_SPLIT_MODE,
ARG_COMPRESS,
ARG_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' },
{ "split-mode", required_argument, NULL, ARG_SPLIT_MODE },
{ "compress", optional_argument, NULL, ARG_COMPRESS },
{ "seal", optional_argument, NULL, ARG_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;
bool type_a, type_b;
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
arg_listen_http = optarg;
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
arg_listen_https = optarg;
break;
case ARG_KEY:
if (arg_key) {
log_error("Key file specified twice");
return -EINVAL;
}
arg_key = strdup(optarg);
if (!arg_key)
return log_oom();
break;
case ARG_CERT:
if (arg_cert) {
log_error("Certificate file specified twice");
return -EINVAL;
}
arg_cert = strdup(optarg);
if (!arg_cert)
return log_oom();
break;
case ARG_TRUST:
if (arg_trust || arg_trust_all) {
log_error("Confusing trusted CA configuration");
return -EINVAL;
}
if (streq(optarg, "all"))
arg_trust_all = true;
else {
#ifdef HAVE_GNUTLS
arg_trust = strdup(optarg);
if (!arg_trust)
return log_oom();
#else
log_error("Option --trust is not available.");
return -EINVAL;
#endif
}
break;
case 'o':
if (arg_output) {
log_error("cannot use --output/-o more than once");
return -EINVAL;
}
arg_output = optarg;
break;
case ARG_SPLIT_MODE:
arg_split_mode = journal_write_split_mode_from_string(optarg);
if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) {
log_error("Invalid split mode: %s", optarg);
return -EINVAL;
}
break;
case ARG_COMPRESS:
if (optarg) {
r = parse_boolean(optarg);
if (r < 0) {
log_error("Failed to parse --compress= parameter.");
return -EINVAL;
}
arg_compress = !!r;
} else
arg_compress = true;
break;
case ARG_SEAL:
if (optarg) {
r = parse_boolean(optarg);
if (r < 0) {
log_error("Failed to parse --seal= parameter.");
return -EINVAL;
}
arg_seal = !!r;
} else
arg_seal = true;
break;
case ARG_GNUTLS_LOG: {
#ifdef HAVE_GNUTLS
const 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:
assert_not_reached("Unknown option code.");
}
if (optind < argc)
arg_files = argv + optind;
type_a = arg_getter || !strv_isempty(arg_files);
type_b = arg_url
|| arg_listen_raw
|| arg_listen_http || arg_listen_https
|| sd_listen_fds(false) > 0;
if (type_a && type_b) {
log_error("Cannot use file input or --getter with "
"--arg-listen-... or socket activation.");
return -EINVAL;
}
if (type_a) {
if (!arg_output) {
log_error("Option --output must be specified with file input or --getter.");
return -EINVAL;
}
arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
}
if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE
&& arg_output && is_dir(arg_output, true) > 0) {
log_error("For SplitMode=none, output must be a file.");
return -EINVAL;
}
if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
&& arg_output && is_dir(arg_output, true) <= 0) {
log_error("For SplitMode=host, output must be a directory.");
return -EINVAL;
}
log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
journal_write_split_mode_to_string(arg_split_mode),
strna(arg_key),
strna(arg_cert),
strna(arg_trust));
return 1 /* work to do */;
}
static int load_certificates(char **key, char **cert, char **trust) {
int r;
r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
if (r < 0) {
log_error("Failed to read key from file '%s': %s",
arg_key ?: PRIV_KEY_FILE, strerror(-r));
return r;
}
r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
if (r < 0) {
log_error("Failed to read certificate from file '%s': %s",
arg_cert ?: CERT_FILE, strerror(-r));
return r;
}
if (arg_trust_all)
log_info("Certificate checking disabled.");
else {
r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
if (r < 0) {
log_error("Failed to read CA certificate file '%s': %s",
arg_trust ?: TRUST_FILE, strerror(-r));
return r;
}
}
return 0;
}
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;
_cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
log_show_color(true);
log_parse_environment();
r = parse_config();
if (r < 0)
return EXIT_FAILURE;
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 (arg_listen_https || https_socket >= 0)
if (load_certificates(&key, &cert, &trust) < 0)
return EXIT_FAILURE;
if (remoteserver_init(&s, key, cert, trust) < 0)
return EXIT_FAILURE;
sd_event_set_watchdog(s.events, true);
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;
}
}
server_destroy(&s);
log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
sd_notify(false, "STATUS=Shutting down...");
free(arg_key);
free(arg_cert);
free(arg_trust);
return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}