#include "macro.h"
#include "strv.h"
#include "fileio.h"
-#include "socket-util.h"
#include "microhttpd-util.h"
#ifdef HAVE_GNUTLS
static char* arg_output = NULL;
static char* arg_url = NULL;
static char* arg_getter = NULL;
-static bool arg_stdin = false;
static char* arg_listen_raw = NULL;
static char* arg_listen_http = NULL;
static char* arg_listen_https = NULL;
+static char** arg_files = NULL;
static int arg_compress = true;
static int arg_seal = false;
+static int http_socket = -1, https_socket = -1;
static char *key_pem = NULL;
static char *cert_pem = NULL;
if (child_pid < 0) {
r = -errno;
log_error("Failed to fork: %m");
- close_pipe(fd);
+ safe_close_pair(fd);
return r;
}
_exit(EXIT_FAILURE);
}
- r = close_pipe(fd);
- if (r < 0)
- log_warning("Failed to close pipe fds: %m");
+ safe_close_pair(fd);
/* Make sure the child goes away when the parent dies */
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
static int spawn_getter(char *getter, char *url) {
int r;
- char _cleanup_strv_free_ **words = NULL, **words2 = NULL;
+ _cleanup_strv_free_ char **words = NULL;
assert(getter);
words = strv_split_quoted(getter);
}
static int open_output(Writer *s, const char* url) {
- char _cleanup_free_ *name, *output = NULL;
+ _cleanup_free_ char *name, *output = NULL;
char *c;
int r;
if (r < 0)
return log_oom();
} else {
- r = is_dir(arg_output);
+ r = is_dir(arg_output, true);
if (r > 0) {
r = asprintf(&output,
"%s/remote-%s.journal", arg_output, name);
typedef struct RemoteServer {
RemoteSource **sources;
- ssize_t sources_size;
- ssize_t active;
+ size_t sources_size;
+ size_t active;
sd_event *events;
sd_event_source *sigterm_event, *sigint_event, *listen_event;
assert(fd >= 0);
assert(source);
- if (!GREEDY_REALLOC0_T(s->sources, s->sources_size, fd + 1))
+ if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
return log_oom();
if (s->sources[fd] == NULL) {
RemoteSource *source;
assert(s);
- assert(fd >= 0);
- assert(fd < s->sources_size);
+ assert(fd >= 0 && fd < (ssize_t) s->sources_size);
source = s->sources[fd];
if (source) {
static int add_source(RemoteServer *s, int fd, const char* name) {
RemoteSource *source = NULL;
- char *realname;
+ _cleanup_free_ char *realname = NULL;
int r;
assert(s);
return log_oom();
}
- log_debug("Creating source for fd:%d (%s)", fd, name);
+ log_debug("Creating source for fd:%d (%s)", fd, realname);
r = get_source_for_fd(s, fd, &source);
if (r < 0) {
- log_error("Failed to create source for fd:%d (%s)", fd, name);
+ log_error("Failed to create source for fd:%d (%s)", fd, realname);
return r;
}
assert(source);
return r;
}
-static int setup_raw_socket(RemoteServer *s, const char *address) {
- int fd, r;
-
- fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
- if (fd < 0)
- return fd;
+static int add_raw_socket(RemoteServer *s, int fd) {
+ int r;
r = sd_event_add_io(s->events, &s->listen_event, fd, EPOLLIN,
dispatch_raw_connection_event, s);
return 0;
}
+static int setup_raw_socket(RemoteServer *s, const char *address) {
+ int fd;
+
+ fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
+ if (fd < 0)
+ return fd;
+
+ return add_raw_socket(s, fd);
+}
+
/**********************************************************************
**********************************************************************
**********************************************************************/
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);
} 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)) {
- assert_not_reached("not implemented");
+ 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);
- output_name = "socket";
} 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) {
- char _cleanup_free_ *url = NULL;
- char _cleanup_strv_free_ **urlv = strv_new(arg_url, "/entries", NULL);
+ _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, "");
output_name = arg_listen_https;
}
- if (arg_stdin) {
- log_info("Reading standard input...");
- r = add_source(s, STDIN_FILENO, "stdin");
+ 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;
-
- output_name = "stdin";
}
if (s->active == 0) {
return -EINVAL;
}
- if (!!n + !!arg_url + !!arg_listen_raw + !!arg_stdin > 1)
+ if (!!n + !!arg_url + !!arg_listen_raw + !!arg_files)
output_name = "multiple";
r = writer_init(&s->writer);
static int server_destroy(RemoteServer *s) {
int r;
- ssize_t i;
+ size_t i;
MHDDaemonWrapper *d;
r = writer_close(&s->writer);
RemoteSource *source;
int r;
- assert(fd < s->sources_size);
+ assert(fd >= 0 && fd < (ssize_t) s->sources_size);
source = s->sources[fd];
assert(source->fd == fd);
**********************************************************************/
static int help(void) {
- printf("%s [OPTIONS...]\n\n"
+ 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"
" --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"
- " --stdin Read events from standard input\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"
ARG_LISTEN_RAW,
ARG_LISTEN_HTTP,
ARG_LISTEN_HTTPS,
- ARG_STDIN,
ARG_GETTER,
ARG_COMPRESS,
ARG_NO_COMPRESS,
{ "listen-raw", required_argument, NULL, ARG_LISTEN_RAW },
{ "listen-http", required_argument, NULL, ARG_LISTEN_HTTP },
{ "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
- { "stdin", no_argument, NULL, ARG_STDIN },
{ "output", required_argument, NULL, 'o' },
{ "compress", no_argument, NULL, ARG_COMPRESS },
{ "no-compress", no_argument, NULL, ARG_NO_COMPRESS },
break;
case ARG_LISTEN_HTTP:
- if (arg_listen_http) {
+ if (arg_listen_http || http_socket >= 0) {
log_error("cannot currently use --listen-http more than once");
return -EINVAL;
}
- arg_listen_http = optarg;
+ 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) {
+ if (arg_listen_https || https_socket >= 0) {
log_error("cannot currently use --listen-https more than once");
return -EINVAL;
}
- arg_listen_https = optarg;
+ 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:
log_error("Option --trust is not available.");
#endif
- case ARG_STDIN:
- arg_stdin = true;
- break;
-
case 'o':
if (arg_output) {
log_error("cannot use --output/-o more than once");
return -EINVAL;
}
- if (optind < argc) {
- log_error("This program takes no positional arguments");
- return -EINVAL;
- }
+ if (optind < argc)
+ arg_files = argv + optind;
return 1 /* work to do */;
}
if (remoteserver_init(&s) < 0)
return EXIT_FAILURE;
- log_debug("%s running as pid %lu",
- program_invocation_short_name, (unsigned long) getpid());
+ log_debug("%s running as pid "PID_FMT,
+ program_invocation_short_name, getpid());
sd_notify(false,
"READY=1\n"
"STATUS=Processing requests...");