journal-gatewayd.c revision e51728b0475f68d0f84c1dca8a02c17c9f5a6a29
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen This file is part of systemd.
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen Copyright 2012 Lennart Poettering
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen systemd is free software; you can redistribute it and/or modify it
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen under the terms of the GNU Lesser General Public License as published by
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen (at your option) any later version.
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen systemd is distributed in the hope that it will be useful, but
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen Lesser General Public License for more details.
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen You should have received a copy of the GNU Lesser General Public License
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersentypedef struct RequestMeta {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersenstatic const char* const mime_types[_OUTPUT_MODE_MAX] = {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen [OUTPUT_EXPORT] = "application/vnd.fdo.journal",
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersenstatic RequestMeta *request_meta(void **connection_cls) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen return sd_journal_open(&m->journal, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersenstatic int request_meta_ensure_tmp(RequestMeta *m) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen /* End of this entry, so let's serialize the next
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen r = sd_journal_previous_skip(m->journal, (uint64_t) -m->n_skip + 1);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen else if (m->n_skip > 0)
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen r = sd_journal_next_skip(m->journal, (uint64_t) m->n_skip + 1);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen log_error_errno(r, "Failed to advance journal pointer: %m");
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen } else if (r == 0) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen r = sd_journal_wait(m->journal, (uint64_t) -1);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen log_error_errno(r, "Couldn't wait for journal event: %m");
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen r = sd_journal_test_cursor(m->journal, m->cursor);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen log_error_errno(r, "Failed to test cursor: %m");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error_errno(r, "Failed to create temporary file: %m");
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen r = output_journal(m->tmp, m->journal, m->mode, 0, OUTPUT_FULL_WIDTH, NULL);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen log_error_errno(r, "Failed to serialize item: %m");
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen log_error_errno(errno, "Failed to retrieve file position: %m");
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen log_error_errno(errno, "Failed to seek to position: %m");
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) {
_cleanup_free_ char *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 mhd_respondf(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to open journal: %s\n", strerror(-r));
if (m->discrete) {
if (!m->cursor)
return mhd_respond(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)
r = request_meta_ensure_tmp(m);
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 mhd_respondf(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 get_virtualization(char **v) {
char *b = NULL;
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
NULL,
if (isempty(b)) {
free(b);
*v = NULL;
static int request_handler_machine(
void *connection_cls) {
char *json;
assert(m);
r = open_journal(m);
return mhd_respondf(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to open journal: %s\n", strerror(-r));
return mhd_respondf(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine machine ID: %s\n", strerror(-r));
return mhd_respondf(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine boot ID: %s\n", strerror(-r));
if (!hostname)
return mhd_respondf(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine disk usage: %s\n", strerror(-r));
return mhd_respondf(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine disk usage: %s\n", strerror(-r));
get_virtualization(&v);
if (!response) {
static int request_handler(
void *cls,
const char *url,
const char *method,
const char *version,
const char *upload_data,
void **connection_cls) {
int r, code;
if (!*connection_cls) {
return MHD_YES;
if (arg_trust_pem) {
return code;
static void help(void) {
help();
case ARG_VERSION:
case ARG_KEY:
if (arg_key_pem) {
return -EINVAL;
case ARG_CERT:
if (arg_cert_pem) {
return -EINVAL;
case ARG_TRUST:
#ifdef HAVE_GNUTLS
if (arg_trust_pem) {
return -EINVAL;
return -EINVAL;
return -EINVAL;
return -EINVAL;
return -EINVAL;
log_open();
return EXIT_FAILURE;
return EXIT_SUCCESS;
return EXIT_FAILURE;
goto finish;
goto finish;
if (arg_key_pem) {
if (arg_trust_pem) {
goto finish;
pause();
r = EXIT_SUCCESS;
MHD_stop_daemon(d);