X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fjournal%2Fjournald.c;h=d35e1c119ab5984604471f1ed08b240ecadc93c7;hb=6ad1d1c30621280bfad3e63fcc1c7ceb7d8ffa98;hp=c457d2786b266ee4e48006bccd4b78dbd800be73;hpb=50f20cfdb0f127e415ab38c024d9ca7a3602f74b;p=elogind.git diff --git a/src/journal/journald.c b/src/journal/journald.c index c457d2786..d35e1c119 100644 --- a/src/journal/journald.c +++ b/src/journal/journald.c @@ -54,6 +54,10 @@ typedef struct Server { char *buffer; size_t buffer_size; + + JournalMetrics metrics; + uint64_t max_use; + bool compress; } Server; static void fix_perms(JournalFile *f, uid_t uid) { @@ -143,6 +147,8 @@ static JournalFile* find_journal(Server *s, uid_t uid) { return s->system_journal; fix_perms(f, uid); + f->metrics = s->metrics; + f->compress = s->compress; r = hashmap_put(s->user_journals, UINT32_TO_PTR(uid), f); if (r < 0) { @@ -153,6 +159,66 @@ static JournalFile* find_journal(Server *s, uid_t uid) { return f; } +static void server_vacuum(Server *s) { + Iterator i; + void *k; + char *p; + char ids[33]; + sd_id128_t machine; + int r; + JournalFile *f; + + log_info("Rotating..."); + + if (s->runtime_journal) { + r = journal_file_rotate(&s->runtime_journal); + if (r < 0) + log_error("Failed to rotate %s: %s", s->runtime_journal->path, strerror(-r)); + } + + if (s->system_journal) { + r = journal_file_rotate(&s->system_journal); + if (r < 0) + log_error("Failed to rotate %s: %s", s->system_journal->path, strerror(-r)); + } + + HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) { + r = journal_file_rotate(&f); + if (r < 0) + log_error("Failed to rotate %s: %s", f->path, strerror(-r)); + else + hashmap_replace(s->user_journals, k, f); + } + + log_info("Vacuuming..."); + + r = sd_id128_get_machine(&machine); + if (r < 0) { + log_error("Failed to get machine ID: %s", strerror(-r)); + return; + } + + if (asprintf(&p, "/var/log/journal/%s", sd_id128_to_string(machine, ids)) < 0) { + log_error("Out of memory."); + return; + } + + r = journal_directory_vacuum(p, s->max_use, s->metrics.keep_free); + if (r < 0 && r != -ENOENT) + log_error("Failed to vacuum %s: %s", p, strerror(-r)); + free(p); + + if (asprintf(&p, "/run/log/journal/%s", ids) < 0) { + log_error("Out of memory."); + return; + } + + r = journal_directory_vacuum(p, s->max_use, s->metrics.keep_free); + if (r < 0 && r != -ENOENT) + log_error("Failed to vacuum %s: %s", p, strerror(-r)); + free(p); +} + static void dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, struct ucred *ucred, struct timeval *tv) { char *pid = NULL, *uid = NULL, *gid = NULL, *source_time = NULL, *boot_id = NULL, *machine_id = NULL, @@ -166,6 +232,7 @@ static void dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigne char *t; uid_t loginuid = 0, realuid = 0; JournalFile *f; + bool vacuumed = false; assert(s); assert(iovec || n == 0); @@ -262,12 +329,23 @@ static void dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigne assert(n <= m); +retry: f = find_journal(s, realuid == 0 ? 0 : loginuid); if (!f) log_warning("Dropping message, as we can't find a place to store the data."); else { r = journal_file_append_entry(f, NULL, iovec, n, &s->seqnum, NULL, NULL); + if (r == -E2BIG && !vacuumed) { + log_info("Allocation limit reached."); + + server_vacuum(s); + vacuumed = true; + + log_info("Retrying write."); + goto retry; + } + if (r < 0) log_error("Failed to write entry, ignoring: %s", strerror(-r)); } @@ -317,6 +395,41 @@ static void process_syslog_message(Server *s, const char *buf, struct ucred *ucr free(syslog_priority); } +static bool valid_user_field(const char *p, size_t l) { + const char *a; + + /* We kinda enforce POSIX syntax recommendations for + environment variables here, but make a couple of additional + requirements. + + http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */ + + /* No empty field names */ + if (l <= 0) + return false; + + /* Don't allow names longer than 64 chars */ + if (l > 64) + return false; + + /* Variables starting with an underscore are protected */ + if (p[0] == '_') + return false; + + /* Don't allow digits as first character */ + if (p[0] >= '0' && p[0] <= '9') + return false; + + /* Only allow A-Z0-9 and '_' */ + for (a = p; a < p + l; a++) + if (!((*a >= 'A' && *a <= 'Z') || + (*a >= '0' && *a <= '9') || + *a == '_')) + return false; + + return true; +} + static void process_native_message(Server *s, const void *buffer, size_t buffer_size, struct ucred *ucred, struct timeval *tv) { struct iovec *iovec = NULL; unsigned n = 0, m = 0, j; @@ -350,8 +463,9 @@ static void process_native_message(Server *s, const void *buffer, size_t buffer_ continue; } - if (*p == '.') { - /* Control command, ignore for now */ + if (*p == '.' || *p == '#') { + /* Ignore control commands for now, and + * comments too. */ remaining -= (e - p) + 1; p = e + 1; continue; @@ -376,7 +490,7 @@ static void process_native_message(Server *s, const void *buffer, size_t buffer_ q = memchr(p, '=', e - p); if (q) { - if (p[0] != '_') { + if (valid_user_field(p, q - p)) { /* If the field name starts with an * underscore, skip the variable, * since that indidates a trusted @@ -417,7 +531,7 @@ static void process_native_message(Server *s, const void *buffer, size_t buffer_ k[e - p] = '='; memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l); - if (k[0] != '_') { + if (valid_user_field(p, e - p)) { iovec[n].iov_base = k; iovec[n].iov_len = (e - p) + 1 + l; n++; @@ -586,6 +700,9 @@ static int system_journal_open(Server *s) { free(fn); if (r >= 0) { + s->system_journal->metrics = s->metrics; + s->system_journal->compress = s->compress; + fix_perms(s->system_journal, 0); return r; } @@ -610,6 +727,9 @@ static int system_journal_open(Server *s) { return r; } + s->runtime_journal->metrics = s->metrics; + s->runtime_journal->compress = s->compress; + fix_perms(s->runtime_journal, 0); return r; } @@ -715,6 +835,11 @@ static int server_init(Server *s) { zero(*s); s->syslog_fd = s->native_fd = s->signal_fd = -1; + s->metrics.max_size = DEFAULT_MAX_SIZE; + s->metrics.min_size = DEFAULT_MIN_SIZE; + s->metrics.keep_free = DEFAULT_KEEP_FREE; + s->max_use = DEFAULT_MAX_USE; + s->compress = true; s->epoll_fd = epoll_create1(EPOLL_CLOEXEC); if (s->epoll_fd < 0) { @@ -852,6 +977,7 @@ int main(int argc, char *argv[]) { } log_set_target(LOG_TARGET_CONSOLE); + log_set_max_level(LOG_DEBUG); log_parse_environment(); log_open();