journal-upload.c revision a3152e7655231b94fa7b9582906fb86ab00b9c99
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering This file is part of systemd.
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering Copyright 2014 Zbigniew Jędrzejewski-Szmek
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering systemd is free software; you can redistribute it and/or modify it
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering under the terms of the GNU Lesser General Public License as published by
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering (at your option) any later version.
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering systemd is distributed in the hope that it will be useful, but
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering Lesser General Public License for more details.
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering You should have received a copy of the GNU Lesser General Public License
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic const char* arg_url;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic bool arg_after_cursor = false;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic bool arg_merge = false;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering#define STATE_FILE "/var/lib/systemd/journal-upload/state"
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering#define easy_setopt(curl, opt, value, level, cmd) \
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering code = curl_easy_setopt(curl, opt, value); \
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering "curl_easy_setopt " #opt " failed: %s", \
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_debug("The server answers (%zu bytes): %.*s",
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_warning("Failed to store server answer (%zu bytes): %s",
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic int update_cursor_state(Uploader *u) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = fopen_temporary(u->state_file, &f, &temp_path);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering "# This is private data. Do not parse.\n"
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering "LAST_CURSOR=%s\n",
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (ferror(f) || rename(temp_path, u->state_file) < 0) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Failed to save state %s: %s", u->state_file, strerror(-r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic int load_cursor_state(Uploader *u) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = parse_env_file(u->state_file, NEWLINE,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (r < 0 && r != -ENOENT) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Failed to read state file %s: %s",
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering h = curl_slist_append(NULL, "Content-Type: application/vnd.fdo.journal");
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering h = curl_slist_append(h, "Transfer-Encoding: chunked");
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering h = curl_slist_append(h, "Accept: text/plain");
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Call to curl_easy_init failed.");
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering /* tell it to POST to the URL */
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering easy_setopt(curl, CURLOPT_ERRORBUFFER, &u->error,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering /* set where to write to */
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering easy_setopt(curl, CURLOPT_WRITEFUNCTION, output_callback,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering easy_setopt(curl, CURLOPT_WRITEDATA, data,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering /* set where to read from */
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering easy_setopt(curl, CURLOPT_READFUNCTION, input_callback,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering easy_setopt(curl, CURLOPT_READDATA, data,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering /* use our special own mime type and chunked transfer */
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering easy_setopt(curl, CURLOPT_HTTPHEADER, u->header,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering /* enable verbose for easier tracing */
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering easy_setopt(curl, CURLOPT_VERBOSE, 1L, LOG_WARNING, );
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering "systemd-journal-upload " PACKAGE_STRING,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering easy_setopt(curl, CURLOPT_SSLKEY, arg_key,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering easy_setopt(curl, CURLOPT_SSLCERT, arg_cert,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering easy_setopt(curl, CURLOPT_CAINFO, arg_trust,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering /* truncate the potential old error message */
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering /* upload to this place */
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering code = curl_easy_setopt(u->easy, CURLOPT_URL, u->url);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("curl_easy_setopt CURLOPT_URL failed: %s",
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic size_t fd_input_callback(void *buf, size_t size, size_t nmemb, void *userp) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_debug("%s: allowed %zu, read %zu", __func__, size*nmemb, r);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Aborting transfer after read error on input: %m.");
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic int dispatch_fd_input(sd_event_source *event,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_warning("dispatch_fd_input called when uploading, ignoring.");
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return start_upload(u, fd_input_callback, u);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic int open_file_for_upload(Uploader *u, const char *filename) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOCTTY);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Failed to open %s: %m", filename);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = sd_event_add_io(u->events, &u->input_event,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Failed to register input event: %s", strerror(-r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering /* Normal files should just be consumed without polling. */
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = start_upload(u, fd_input_callback, u);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic int dispatch_sigterm(sd_event_source *event,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering sigset_add_many(&mask, SIGINT, SIGTERM, -1);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = sd_event_add_signal(u->events, &u->sigterm_event, SIGTERM, dispatch_sigterm, u);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = sd_event_add_signal(u->events, &u->sigint_event, SIGINT, dispatch_sigterm, u);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic int setup_uploader(Uploader *u, const char *url, const char *state_file) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("sd_event_default failed: %s", strerror(-r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Failed to set up signals: %s", strerror(-r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic void destroy_uploader(Uploader *u) {
close_fd_input(u);
long status;
assert(u);
if (code) {
u->url,
return -EIO;
if (code) {
return -EUCLEAN;
return -EIO;
return -EIO;
return update_cursor_state(u);
static void help(void) {
opterr = 0;
help();
case ARG_VERSION:
if (arg_url) {
return -EINVAL;
case ARG_KEY:
if (arg_key) {
return -EINVAL;
case ARG_CERT:
if (arg_cert) {
return -EINVAL;
case ARG_TRUST:
if (arg_trust) {
return -EINVAL;
case ARG_SYSTEM:
case ARG_USER:
arg_merge = true;
if (arg_machine) {
return -EINVAL;
if (arg_directory) {
return -EINVAL;
case ARG_FILE:
case ARG_CURSOR:
if (arg_cursor) {
return -EINVAL;
case ARG_AFTER_CURSOR:
if (arg_cursor) {
return -EINVAL;
arg_after_cursor = true;
case ARG_FOLLOW:
arg_follow = true;
case ARG_NO_FOLLOW:
arg_follow = false;
case ARG_SAVE_STATE:
return -EINVAL;
return -EINVAL;
if (!arg_url) {
return -EINVAL;
return -EINVAL;
return -EINVAL;
if (arg_directory)
else if (arg_file)
else if (arg_machine)
strerror(-r));
Uploader u;
bool use_journal;
log_show_color(true);
goto finish;
goto cleanup;
if (use_journal) {
sd_journal *j;
r = open_journal(&j);
goto finish;
r = open_journal_for_upload(&u, j,
!!arg_follow);
goto finish;
sd_notify(false,
if (use_journal) {
if (!u.journal)
r = check_journal_input(&u);
goto cleanup;
if (r == SD_EVENT_FINISHED)
if (u.uploading) {
r = perform_upload(&u);
destroy_uploader(&u);