journal-upload.c revision 07630cea1f3a845c09309f197ac7c4f11edd3b62
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2014 Zbigniew Jędrzejewski-Szmek
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU Lesser General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Lesser General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU Lesser General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering#define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-upload.pem"
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering#define CERT_FILE CERTIFICATE_ROOT "/certs/journal-upload.pem"
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering#define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic bool arg_after_cursor = false;
a0166609f782da91710dea9183d1bf138538db37Tom Gundersenstatic bool arg_merge = false;
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering#define STATE_FILE "/var/lib/systemd/journal-upload/state"
d74fb368b18f0fbd9a4fe6f15691bbea7f3c4a01Tom Gundersen#define easy_setopt(curl, opt, value, level, cmd) \
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "curl_easy_setopt " #opt " failed: %s", \
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering log_debug("The server answers (%zu bytes): %.*s",
9c491563837983385bf9fa244590e76e142f4fa3Daniel Mack log_warning_errno(ENOMEM, "Failed to store server answer (%zu bytes): %m",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int check_cursor_updating(Uploader *u) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return log_error_errno(r, "Cannot create parent directory of state file %s: %m",
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering r = fopen_temporary(u->state_file, &f, &temp_path);
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering return log_error_errno(r, "Cannot save state to %s: %m",
f3abbe25403444688e1a1a23b9dbcc9aeefc0507Lennart Poetteringstatic int update_cursor_state(Uploader *u) {
f3abbe25403444688e1a1a23b9dbcc9aeefc0507Lennart Poettering r = fopen_temporary(u->state_file, &f, &temp_path);
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack "# This is private data. Do not parse.\n"
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack "LAST_CURSOR=%s\n",
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering if (rename(temp_path, u->state_file) < 0) {
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering return log_error_errno(r, "Failed to save state %s: %m", u->state_file);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poetteringstatic int load_cursor_state(Uploader *u) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_debug("State file %s is not present.", u->state_file);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering else if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return log_error_errno(r, "Failed to read state file %s: %m",
8af5b883227ac8dfa796742b9edcc1647a5d4d6cLennart Poettering log_debug("Last cursor was %s", u->last_cursor);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering h = curl_slist_append(NULL, "Content-Type: application/vnd.fdo.journal");
d2579eec5e1b845b2cf29caddc951dc22f2abb91Lennart Poettering h = curl_slist_append(h, "Transfer-Encoding: chunked");
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering h = curl_slist_append(h, "Accept: text/plain");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_error("Call to curl_easy_init failed.");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* tell it to POST to the URL */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering easy_setopt(curl, CURLOPT_ERRORBUFFER, u->error,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* set where to write to */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering easy_setopt(curl, CURLOPT_WRITEFUNCTION, output_callback,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering easy_setopt(curl, CURLOPT_WRITEDATA, data,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* set where to read from */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering easy_setopt(curl, CURLOPT_READFUNCTION, input_callback,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering easy_setopt(curl, CURLOPT_READDATA, data,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering /* use our special own mime type and chunked transfer */
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering easy_setopt(curl, CURLOPT_HTTPHEADER, u->header,
0db4c90afd7d9c7c8884bf8b3ec459edc74a03daDaniel Mack if (_unlikely_(log_get_max_level() >= LOG_DEBUG))
b6c5d46b23a28b5b03601ee1e8162b1bc7c7be25Daniel Mack /* enable verbose for easier tracing */
0db4c90afd7d9c7c8884bf8b3ec459edc74a03daDaniel Mack easy_setopt(curl, CURLOPT_VERBOSE, 1L, LOG_WARNING, );
51323288fc628a5cac50914df915545d685b793eLennart Poettering "systemd-journal-upload " PACKAGE_STRING,
931851e8e492a4d2715e22dcde50a5e7ccef4b49Lennart Poettering if (arg_key || startswith(u->url, "https://")) {
51323288fc628a5cac50914df915545d685b793eLennart Poettering easy_setopt(curl, CURLOPT_SSLKEY, arg_key ?: PRIV_KEY_FILE,
106784ebb7b303ae471851100a773ad2aebf5b80Daniel Mack easy_setopt(curl, CURLOPT_SSLCERT, arg_cert ?: CERT_FILE,
51323288fc628a5cac50914df915545d685b793eLennart Poettering easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0,
4e5bf5e15899de3f9d11c2ddfe9721d9f8b07a37Daniel Mack else if (arg_trust || startswith(u->url, "https://"))
4e5bf5e15899de3f9d11c2ddfe9721d9f8b07a37Daniel Mack easy_setopt(curl, CURLOPT_CAINFO, arg_trust ?: TRUST_FILE,
106784ebb7b303ae471851100a773ad2aebf5b80Daniel Mack easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1,
u->answer = 0;
if (code) {
return -EXFULL;
u->uploading = true;
ssize_t r;
assert(u);
if (u->input < 0)
u->uploading = false;
close_fd_input(u);
return CURL_READFUNC_ABORT;
assert(u);
if (u->input >= 0)
u->timeout = 0;
int fd,
void *userp) {
assert(u);
close_fd_input(u);
return -EINVAL;
if (u->uploading) {
int fd, r = 0;
if (fd < 0)
if (arg_follow) {
void *userdata) {
assert(u);
close_fd_input(u);
assert(u);
assert(u);
size_t x;
x = strlen(t);
if (!u->url)
return log_oom();
r = setup_signals(u);
return load_cursor_state(u);
assert(u);
close_fd_input(u);
long status;
assert(u);
if (code) {
if (u->error[0])
return -EIO;
if (code) {
return -EUCLEAN;
return -EIO;
return -EIO;
return update_cursor_state(u);
static int parse_config(void) {
false, NULL);
static void help(void) {
opterr = 0;
help();
case ARG_VERSION:
return 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:
if (optarg) {
return -EINVAL;
arg_follow = !!r;
arg_follow = true;
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)
Uploader u;
bool use_journal;
log_show_color(true);
r = parse_config();
goto finish;
goto finish;
goto cleanup;
r = check_cursor_updating(&u);
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 (r == SD_EVENT_FINISHED)
if (use_journal) {
if (!u.journal)
r = check_journal_input(&u);
goto cleanup;
if (u.uploading) {
r = perform_upload(&u);
sd_notify(false,
destroy_uploader(&u);