summaryrefslogtreecommitdiffstats
path: root/src/journal-remote/journal-gatewayd.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/journal-remote/journal-gatewayd.c207
1 files changed, 148 insertions, 59 deletions
diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c
index aaa52c0..dd91f22 100644
--- a/src/journal-remote/journal-gatewayd.c
+++ b/src/journal-remote/journal-gatewayd.c
@@ -22,6 +22,8 @@
#include "fileio.h"
#include "glob-util.h"
#include "hostname-util.h"
+#include "journal-internal.h"
+#include "journal-remote.h"
#include "log.h"
#include "logs-show.h"
#include "main-func.h"
@@ -32,6 +34,7 @@
#include "pretty-print.h"
#include "sigbus.h"
#include "signal-util.h"
+#include "time-util.h"
#include "tmpfile-util.h"
#define JOURNAL_WAIT_TIMEOUT (10*USEC_PER_SEC)
@@ -55,9 +58,10 @@ typedef struct RequestMeta {
OutputMode mode;
char *cursor;
+ usec_t since, until;
int64_t n_skip;
uint64_t n_entries;
- bool n_entries_set;
+ bool n_entries_set, since_set, until_set;
FILE *tmp;
uint64_t delta, size;
@@ -212,6 +216,17 @@ static ssize_t request_reader_entries(
return MHD_CONTENT_READER_END_OF_STREAM;
}
+ if (m->until_set) {
+ usec_t usec;
+
+ r = sd_journal_get_realtime_usec(m->journal, &usec);
+ if (r < 0) {
+ log_error_errno(r, "Failed to determine timestamp: %m");
+ return MHD_CONTENT_READER_END_WITH_ERROR;
+ }
+ if (usec > m->until)
+ return MHD_CONTENT_READER_END_OF_STREAM;
+ }
pos -= m->size;
m->delta += m->size;
@@ -293,60 +308,59 @@ static int request_parse_accept(
return 0;
}
-static int request_parse_range(
+static int request_parse_range_skip_and_n_entries(
RequestMeta *m,
- struct MHD_Connection *connection) {
+ const char *colon) {
- const char *range, *colon, *colon2;
+ const char *p, *colon2;
int r;
- assert(m);
- assert(connection);
+ colon2 = strchr(colon + 1, ':');
+ if (colon2) {
+ _cleanup_free_ char *t = NULL;
- range = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Range");
- if (!range)
- return 0;
+ t = strndup(colon + 1, colon2 - colon - 1);
+ if (!t)
+ return -ENOMEM;
- if (!startswith(range, "entries="))
- return 0;
+ r = safe_atoi64(t, &m->n_skip);
+ if (r < 0)
+ return r;
+ }
- range += 8;
- range += strspn(range, WHITESPACE);
+ p = (colon2 ?: colon) + 1;
+ r = safe_atou64(p, &m->n_entries);
+ if (r < 0)
+ return r;
- colon = strchr(range, ':');
- if (!colon)
- m->cursor = strdup(range);
- else {
- const char *p;
+ if (m->n_entries <= 0)
+ return -EINVAL;
- colon2 = strchr(colon + 1, ':');
- if (colon2) {
- _cleanup_free_ char *t = NULL;
+ m->n_entries_set = true;
- t = strndup(colon + 1, colon2 - colon - 1);
- if (!t)
- return -ENOMEM;
+ return 0;
+}
- r = safe_atoi64(t, &m->n_skip);
- if (r < 0)
- return r;
- }
+static int request_parse_range_entries(
+ RequestMeta *m,
+ const char *entries_request) {
- p = (colon2 ?: colon) + 1;
- if (*p) {
- r = safe_atou64(p, &m->n_entries);
- if (r < 0)
- return r;
+ const char *colon;
+ int r;
- if (m->n_entries <= 0)
- return -EINVAL;
+ assert(m);
+ assert(entries_request);
- m->n_entries_set = true;
- }
+ colon = strchr(entries_request, ':');
+ if (!colon)
+ m->cursor = strdup(entries_request);
+ else {
+ r = request_parse_range_skip_and_n_entries(m, colon);
+ if (r < 0)
+ return r;
- m->cursor = strndup(range, colon - range);
+ m->cursor = strndup(entries_request, colon - entries_request);
}
-
if (!m->cursor)
return -ENOMEM;
@@ -357,6 +371,93 @@ static int request_parse_range(
return 0;
}
+static int request_parse_range_time(
+ RequestMeta *m,
+ const char *time_request) {
+
+ _cleanup_free_ char *until = NULL;
+ const char *colon;
+ int r;
+
+ assert(m);
+ assert(time_request);
+
+ colon = strchr(time_request, ':');
+ if (!colon)
+ return -EINVAL;
+
+ if (colon - time_request > 0) {
+ _cleanup_free_ char *t = NULL;
+
+ t = strndup(time_request, colon - time_request);
+ if (!t)
+ return -ENOMEM;
+
+ r = parse_sec(t, &m->since);
+ if (r < 0)
+ return r;
+
+ m->since_set = true;
+ }
+
+ time_request = colon + 1;
+ colon = strchr(time_request, ':');
+ if (!colon)
+ until = strdup(time_request);
+ else {
+ r = request_parse_range_skip_and_n_entries(m, colon);
+ if (r < 0)
+ return r;
+
+ until = strndup(time_request, colon - time_request);
+ }
+ if (!until)
+ return -ENOMEM;
+
+ if (!isempty(until)) {
+ r = parse_sec(until, &m->until);
+ if (r < 0)
+ return r;
+
+ m->until_set = true;
+ if (m->until < m->since)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int request_parse_range(
+ RequestMeta *m,
+ struct MHD_Connection *connection) {
+
+ const char *range, *range_after_eq;
+
+ assert(m);
+ assert(connection);
+
+ range = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Range");
+ if (!range)
+ return 0;
+
+ /* Safety upper bound to make Coverity happy. Apache2 has a default limit of 8KB:
+ * https://httpd.apache.org/docs/2.2/mod/core.html#limitrequestfieldsize */
+ if (strlen(range) > JOURNAL_SERVER_MEMORY_MAX)
+ return -EINVAL;
+
+ m->n_skip = 0;
+
+ range_after_eq = startswith(range, "entries=");
+ if (range_after_eq)
+ return request_parse_range_entries(m, skip_leading_chars(range_after_eq, /* bad = */ NULL));
+
+ range_after_eq = startswith(range, "realtime=");
+ if (range_after_eq)
+ return request_parse_range_time(m, skip_leading_chars(range_after_eq, /* bad = */ NULL));
+
+ return 0;
+}
+
static mhd_result request_parse_arguments_iterator(
void *cls,
enum MHD_ValueKind kind,
@@ -364,7 +465,6 @@ static mhd_result request_parse_arguments_iterator(
const char *value) {
RequestMeta *m = ASSERT_PTR(cls);
- _cleanup_free_ char *p = NULL;
int r;
if (isempty(key)) {
@@ -416,17 +516,7 @@ static mhd_result request_parse_arguments_iterator(
}
if (r) {
- char match[9 + 32 + 1] = "_BOOT_ID=";
- sd_id128_t bid;
-
- r = sd_id128_get_boot(&bid);
- if (r < 0) {
- log_error_errno(r, "Failed to get boot ID: %m");
- return MHD_NO;
- }
-
- sd_id128_to_string(bid, match + 9);
- r = sd_journal_add_match(m->journal, match, sizeof(match)-1);
+ r = add_match_boot_id(m->journal, SD_ID128_NULL);
if (r < 0) {
m->argument_parse_error = r;
return MHD_NO;
@@ -436,13 +526,7 @@ static mhd_result request_parse_arguments_iterator(
return MHD_YES;
}
- p = strjoin(key, "=", strempty(value));
- if (!p) {
- m->argument_parse_error = log_oom();
- return MHD_NO;
- }
-
- r = sd_journal_add_match(m->journal, p, 0);
+ r = journal_add_match_pair(m->journal, key, strempty(value));
if (r < 0) {
m->argument_parse_error = r;
return MHD_NO;
@@ -497,10 +581,15 @@ static int request_handler_entries(
if (m->cursor)
r = sd_journal_seek_cursor(m->journal, m->cursor);
+ else if (m->since_set)
+ r = sd_journal_seek_realtime_usec(m->journal, m->since);
else if (m->n_skip >= 0)
r = sd_journal_seek_head(m->journal);
+ else if (m->until_set && m->n_skip < 0)
+ r = sd_journal_seek_realtime_usec(m->journal, m->until);
else if (m->n_skip < 0)
r = sd_journal_seek_tail(m->journal);
+
if (r < 0)
return mhd_respond(connection, MHD_HTTP_BAD_REQUEST, "Failed to seek in journal.");
@@ -778,7 +867,7 @@ static int request_handler_machine(
SD_ID128_FORMAT_VAL(bid),
hostname_cleanup(hostname),
os_release_pretty_name(pretty_name, os_name),
- v ? v : "bare",
+ v ?: "bare",
usage,
cutoff_from,
cutoff_to);