FILE *tmp;
uint64_t delta, size;
+
+ int argument_parse_error;
+
+ bool follow;
+ bool discrete;
} RequestMeta;
static const char* const mime_types[_OUTPUT_MODE_MAX] = {
m->n_entries <= 0)
return MHD_CONTENT_READER_END_OF_STREAM;
- if (m->n_skip < 0) {
- r = sd_journal_previous_skip(m->journal, (uint64_t) -m->n_skip);
-
- /* We couldn't seek this far backwards? Then
- * let's try to look forward... */
- if (r == 0)
- r = sd_journal_next(m->journal);
-
- } else if (m->n_skip > 0)
+ if (m->n_skip < 0)
+ r = sd_journal_previous_skip(m->journal, (uint64_t) -m->n_skip + 1);
+ else if (m->n_skip > 0)
r = sd_journal_next_skip(m->journal, (uint64_t) m->n_skip + 1);
else
r = sd_journal_next(m->journal);
if (r < 0) {
log_error("Failed to advance journal pointer: %s", strerror(-r));
return MHD_CONTENT_READER_END_WITH_ERROR;
- } else if (r == 0)
+ } else if (r == 0) {
+
+ if (m->follow) {
+ r = sd_journal_wait(m->journal, (uint64_t) -1);
+ if (r < 0) {
+ log_error("Couldn't wait for journal event: %s", strerror(-r));
+ return MHD_CONTENT_READER_END_WITH_ERROR;
+ }
+
+ continue;
+ }
+
return MHD_CONTENT_READER_END_OF_STREAM;
+ }
+
+ if (m->discrete) {
+ assert(m->cursor);
+
+ r = sd_journal_test_cursor(m->journal, m->cursor);
+ if (r < 0) {
+ log_error("Failed to test cursor: %s", strerror(-r));
+ return MHD_CONTENT_READER_END_WITH_ERROR;
+ }
+
+ if (r == 0)
+ return MHD_CONTENT_READER_END_OF_STREAM;
+ }
pos -= m->size;
m->delta += m->size;
return 0;
}
+static int request_parse_arguments_iterator(
+ void *cls,
+ enum MHD_ValueKind kind,
+ const char *key,
+ const char *value) {
+
+ RequestMeta *m = cls;
+ _cleanup_free_ char *p = NULL;
+ int r;
+
+ assert(m);
+
+ if (isempty(key)) {
+ m->argument_parse_error = -EINVAL;
+ return MHD_NO;
+ }
+
+ if (streq(key, "follow")) {
+ if (isempty(value)) {
+ m->follow = true;
+ return MHD_YES;
+ }
+
+ r = parse_boolean(value);
+ if (r < 0) {
+ m->argument_parse_error = r;
+ return MHD_NO;
+ }
+
+ m->follow = r;
+ return MHD_YES;
+ }
+
+ if (streq(key, "discrete")) {
+ if (isempty(value)) {
+ m->discrete = true;
+ return MHD_YES;
+ }
+
+ r = parse_boolean(value);
+ if (r < 0) {
+ m->argument_parse_error = r;
+ return MHD_NO;
+ }
+
+ m->discrete = r;
+ return MHD_YES;
+ }
+
+ p = strjoin(key, "=", strempty(value), NULL);
+ if (!p) {
+ m->argument_parse_error = log_oom();
+ return MHD_NO;
+ }
+
+ r = sd_journal_add_match(m->journal, p, 0);
+ if (r < 0) {
+ m->argument_parse_error = r;
+ return MHD_NO;
+ }
+
+ return MHD_YES;
+}
+
+static int request_parse_arguments(
+ RequestMeta *m,
+ struct MHD_Connection *connection) {
+
+ assert(m);
+ assert(connection);
+
+ m->argument_parse_error = 0;
+ MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, request_parse_arguments_iterator, m);
+
+ return m->argument_parse_error;
+}
+
static int request_handler_entries(
struct MHD_Connection *connection,
void **connection_cls) {
if (request_parse_range(m, connection) < 0)
return respond_error(connection, MHD_HTTP_BAD_REQUEST, "Failed to parse Range header.\n");
- /* log_info("cursor = %s", m->cursor); */
- /* log_info("skip = %lli", m->n_skip); */
- /* if (!m->n_entries_set) */
- /* log_info("n_entries not set!"); */
- /* else */
- /* log_info("n_entries = %llu", m->n_entries); */
+ if (request_parse_arguments(m, connection) < 0)
+ return respond_error(connection, MHD_HTTP_BAD_REQUEST, "Failed to parse URL arguments.\n");
+
+ if (m->discrete) {
+ if (!m->cursor)
+ return respond_error(connection, MHD_HTTP_BAD_REQUEST, "Discrete seeks require a cursor specification.\n");
+
+ m->n_entries = 1;
+ m->n_entries_set = true;
+ }
if (m->cursor)
r = sd_journal_seek_cursor(m->journal, m->cursor);
goto finish;
}
- log_set_target(LOG_TARGET_KMSG);
+ log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
log_open();