journal-gatewayd.c revision a860325e7ed7ea2bd688b2f002021123a05af084
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer This file is part of systemd.
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Copyright 2012 Lennart Poettering
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer systemd is free software; you can redistribute it and/or modify it
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer under the terms of the GNU Lesser General Public License as published by
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer the Free Software Foundation; either version 2.1 of the License, or
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer (at your option) any later version.
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer systemd is distributed in the hope that it will be useful, but
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer WITHOUT ANY WARRANTY; without even the implied warranty of
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Lesser General Public License for more details.
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer You should have received a copy of the GNU Lesser General Public License
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer along with systemd; If not, see <http://www.gnu.org/licenses/>.
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyertypedef struct RequestMeta {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic const char* const mime_types[_OUTPUT_MODE_MAX] = {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [OUTPUT_EXPORT] = "application/vnd.fdo.journal",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic RequestMeta *request_meta(void **connection_cls) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return sd_journal_open(&m->journal, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int respond_oom_internal(struct MHD_Connection *connection) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const char m[] = "Out of memory.\n";
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer response = MHD_create_response_from_buffer(sizeof(m)-1, (char*) m, MHD_RESPMEM_PERSISTENT);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer MHD_add_response_header(response, "Content-Type", "text/plain");
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer ret = MHD_queue_response(connection, MHD_HTTP_SERVICE_UNAVAILABLE, response);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#define respond_oom(connection) log_oom(), respond_oom_internal(connection)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const char *format, ...) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer response = MHD_create_response_from_buffer(strlen(m), m, MHD_RESPMEM_MUST_FREE);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer MHD_add_response_header(response, "Content-Type", "text/plain");
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = MHD_queue_response(connection, code, response);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* End of this entry, so let's serialize the next
if (m->n_skip < 0)
else if (m->n_skip > 0)
if (m->follow) {
return MHD_CONTENT_READER_END_OF_STREAM;
if (m->discrete) {
return MHD_CONTENT_READER_END_OF_STREAM;
if (m->n_entries_set)
m->n_skip = 0;
if (m->tmp)
if (!m->tmp) {
if (n > max)
n = max;
errno = 0;
return (ssize_t) k;
static int request_parse_accept(
RequestMeta *m,
const char *header;
assert(m);
if (!header)
static int request_parse_range(
RequestMeta *m,
assert(m);
if (!range)
if (!colon)
if (colon2) {
char _cleanup_free_ *t;
return -ENOMEM;
if (m->n_entries <= 0)
return -EINVAL;
m->n_entries_set = true;
if (!m->cursor)
return -ENOMEM;
static int request_parse_arguments_iterator(
void *cls,
const char *key,
const char *value) {
assert(m);
return MHD_NO;
m->follow = true;
return MHD_YES;
m->argument_parse_error = r;
return MHD_NO;
m->follow = r;
return MHD_YES;
m->discrete = true;
return MHD_YES;
m->argument_parse_error = r;
return MHD_NO;
m->discrete = r;
return MHD_YES;
m->argument_parse_error = r;
return MHD_NO;
return MHD_NO;
m->argument_parse_error = r;
return MHD_NO;
return MHD_YES;
return MHD_NO;
m->argument_parse_error = r;
return MHD_NO;
return MHD_YES;
static int request_parse_arguments(
RequestMeta *m,
assert(m);
m->argument_parse_error = 0;
return m->argument_parse_error;
static int request_handler_entries(
void *connection_cls) {
assert(m);
r = open_journal(m);
return respond_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to open journal: %s\n", strerror(-r));
if (m->discrete) {
if (!m->cursor)
return respond_error(connection, MHD_HTTP_BAD_REQUEST, "Discrete seeks require a cursor specification.\n");
m->n_entries_set = true;
if (m->cursor)
else if (m->n_skip >= 0)
else if (m->n_skip < 0)
response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 4*1024, request_reader_entries, m, NULL);
if (!response)
const char *eq;
size_t j;
if (!eq)
return -EINVAL;
if (m == OUTPUT_JSON) {
void *cls,
char *buf,
size_t n, k;
assert(m);
size_t l;
if (m->n_fields_set &&
m->n_fields <= 0)
return MHD_CONTENT_READER_END_OF_STREAM;
return MHD_CONTENT_READER_END_OF_STREAM;
if (m->n_fields_set)
if (m->tmp)
if (!m->tmp) {
if (n > max)
n = max;
errno = 0;
return (ssize_t) k;
static int request_handler_fields(
const char *field,
void *connection_cls) {
assert(m);
r = open_journal(m);
return respond_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to open journal: %s\n", strerror(-r));
response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 4*1024, request_reader_fields, m, NULL);
if (!response)
MHD_add_response_header(response, "Content-Type", mime_types[m->mode == OUTPUT_JSON ? OUTPUT_JSON : OUTPUT_SHORT]);
static int request_handler_redirect(
const char *target) {
char *page;
int ret;
if (asprintf(&page, "<html><body>Please continue to the <a href=\"%s\">journal browser</a>.</body></html>", target) < 0)
if (!response) {
return ret;
static int request_handler_file(
const char *path,
const char *mime_type) {
int ret;
if (fd < 0)
if (!response)
return ret;
static int request_handler_machine(
void *connection_cls) {
char *json;
assert(m);
r = open_journal(m);
return respond_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to open journal: %s\n", strerror(-r));
return respond_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine machine ID: %s\n", strerror(-r));
return respond_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine boot ID: %s\n", strerror(-r));
if (!hostname)
return respond_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine disk usage: %s\n", strerror(-r));
return respond_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine disk usage: %s\n", strerror(-r));
(unsigned long long) usage,
(unsigned long long) cutoff_from,
(unsigned long long) cutoff_to);
if (!response) {
static int request_handler(
void *cls,
const char *url,
const char *method,
const char *version,
const char *upload_data,
void **connection_cls) {
if (!*connection_cls) {
return MHD_YES;
static int help(void) {
case ARG_VERSION:
return help();
case ARG_KEY:
if (key_pem) {
return -EINVAL;
case ARG_CERT:
if (cert_pem) {
return -EINVAL;
return -EINVAL;
return -EINVAL;
return -EINVAL;
return -EINVAL;
log_open();
return EXIT_FAILURE;
return EXIT_SUCCESS;
goto finish;
goto finish;
if (key_pem) {
goto finish;
pause();
r = EXIT_SUCCESS;
MHD_stop_daemon(d);