b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering This file is part of systemd.
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering Copyright 2014 Zbigniew Jędrzejewski-Szmek
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering systemd is free software; you can redistribute it and/or modify it
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering under the terms of the GNU Lesser General Public License as published by
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering (at your option) any later version.
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering systemd is distributed in the hope that it will be useful, but
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering Lesser General Public License for more details.
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering You should have received a copy of the GNU Lesser General Public License
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek * Write up to size bytes to buf. Return negative on error, and number of
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek * bytes written otherwise. The last case is a kind of an error too.
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekstatic ssize_t write_entry(char *buf, size_t size, Uploader *u) {
a1e58e8ee1c84b633d6d6d651d5328d4dd4eba5bLennart Poettering u->current_cursor = mfree(u->current_cursor);
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek r = sd_journal_get_cursor(u->journal, &u->current_cursor);
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt return log_error_errno(r, "Failed to get cursor: %m");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = snprintf(buf + pos, size - pos,
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek "__CURSOR=%s\n", u->current_cursor);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek /* not enough space */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek /* exactly one character short, but we don't need it */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek } /* fall through */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = sd_journal_get_realtime_usec(u->journal, &realtime);
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt return log_error_errno(r, "Failed to get realtime timestamp: %m");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = snprintf(buf + pos, size - pos,
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek "__REALTIME_TIMESTAMP="USEC_FMT"\n", realtime);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek /* not enough space */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek /* exactly one character short, but we don't need it */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek } /* fall through */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = sd_journal_get_monotonic_usec(u->journal, &monotonic, &boot_id);
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt return log_error_errno(r, "Failed to get monotonic timestamp: %m");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = snprintf(buf + pos, size - pos,
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek "__MONOTONIC_TIMESTAMP="USEC_FMT"\n", monotonic);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek /* not enough space */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek /* exactly one character short, but we don't need it */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek } /* fall through */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = sd_journal_get_monotonic_usec(u->journal, NULL, &boot_id);
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt return log_error_errno(r, "Failed to get monotonic timestamp: %m");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = snprintf(buf + pos, size - pos,
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek "_BOOT_ID=%s\n", sd_id128_to_string(boot_id, sid));
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek /* not enough space */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek /* exactly one character short, but we don't need it */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek } /* fall through */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = sd_journal_enumerate_data(u->journal,
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt return log_error_errno(r, "Failed to move to next field in entry: %m");
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt else if (r == 0) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (!utf8_is_printable_newline(u->field_data,
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek u->entry_state = ENTRY_BINARY_FIELD_START;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek } /* fall through */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek done = size - pos > u->field_length - u->field_pos;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek tocopy = u->field_length - u->field_pos;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek (char*) u->field_data + u->field_pos,
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek u->entry_state = ENTRY_NEW_FIELD;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek case ENTRY_BINARY_FIELD_START: {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek c = memchr(u->field_data, '=', u->field_length);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (!c || c == u->field_data) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek len = c - (const char*)u->field_data;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek /* need space for label + '\n' */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek memcpy(buf + pos, u->field_data, len);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek } /* fall through */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek /* need space for uint64_t */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek le64 = htole64(u->field_length - u->field_pos);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek /* need space for '\n' */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekstatic size_t journal_input_callback(void *buf, size_t size, size_t nmemb, void *userp) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek assert(nmemb <= SSIZE_MAX / size);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek while (j && filled < size * nmemb) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (u->entry_state == ENTRY_DONE) {
c33b329709ebe2755181980a050d02ec7c81ed87Michal Schmidt log_error_errno(r, "Failed to move to next entry in journal: %m");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek } else if (r == 0) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_debug("No more entries, waiting for journal.");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_info("No more entries, closing journal.");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek w = write_entry((char*)buf + filled, size * nmemb - filled, u);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_error("Buffer space is too small to write entry.");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek } else if (u->entry_state != ENTRY_DONE)
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek /* This means that all available space was used up */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_debug("Entry %zu (%s) has been uploaded.",
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek u->entries_sent, u->current_cursor);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekvoid close_journal_input(Uploader *u) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_debug("Closing journal input.");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekstatic int process_journal_input(Uploader *u, int skip) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = sd_journal_next_skip(u->journal, skip);
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt return log_error_errno(r, "Failed to skip to next entry: %m");
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt else if (r < skip)
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek return start_upload(u, journal_input_callback, u);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekint check_journal_input(Uploader *u) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = sd_journal_process(u->journal);
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_error_errno(r, "Failed to process journal: %m");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek return process_journal_input(u, 1);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekstatic int dispatch_journal_input(sd_event_source *event,
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_debug("Detected journal input, checking for new data.");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekint open_journal_for_upload(Uploader *u,
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek sd_journal_set_data_threshold(j, 0);
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt return log_error_errno(fd, "sd_journal_get_fd failed: %m");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek events = sd_journal_get_events(j);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek u->timeout = JOURNAL_UPLOAD_POLL_TIMEOUT;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = sd_event_add_io(u->events, &u->input_event,
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek fd, events, dispatch_journal_input, u);
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt return log_error_errno(r, "Failed to register input event: %m");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_debug("Listening for journal events on fd:%d, timeout %d",
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek fd, u->timeout == (uint64_t) -1 ? -1 : (int) u->timeout);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_debug("Not listening for journal events.");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = sd_journal_seek_cursor(j, cursor);
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt return log_error_errno(r, "Failed to seek to cursor %s: %m",