journald-server.c revision 3bfd4e0c6341b0ef946d2198f089743fa99e0a97
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte This file is part of systemd.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte Copyright 2011 Lennart Poettering
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte systemd is free software; you can redistribute it and/or modify it
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte under the terms of the GNU Lesser General Public License as published by
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte the Free Software Foundation; either version 2.1 of the License, or
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (at your option) any later version.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte systemd is distributed in the hope that it will be useful, but
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte WITHOUT ANY WARRANTY; without even the implied warranty of
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte Lesser General Public License for more details.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte You should have received a copy of the GNU Lesser General Public License
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte along with systemd; If not, see <http://www.gnu.org/licenses/>.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#define DEFAULT_SYNC_INTERVAL_USEC (5*USEC_PER_MINUTE)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#define DEFAULT_RATE_LIMIT_INTERVAL (30*USEC_PER_SEC)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#define RECHECK_AVAILABLE_SPACE_USEC (30*USEC_PER_SEC)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic const char* const storage_table[_STORAGE_MAX] = {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn ForteDEFINE_CONFIG_PARSE_ENUM(config_parse_storage, storage, Storage, "Failed to parse storage setting");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic const char* const split_mode_table[_SPLIT_MAX] = {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn ForteDEFINE_STRING_TABLE_LOOKUP(split_mode, SplitMode);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn ForteDEFINE_CONFIG_PARSE_ENUM(config_parse_split_mode, split_mode, SplitMode, "Failed to parse split mode setting");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic uint64_t available_space(Server *s, bool verbose) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte const char *f;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (s->cached_available_space_timestamp + RECHECK_AVAILABLE_SPACE_USEC > ts
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte p = strappend(f, sd_id128_to_string(machine, ids));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* If we reached a high mark, we will always allow this much
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * again, unless usage goes above max_use. This watermark
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * value is cached so that we don't give up space on pressure,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * but hover below the maximum usage. */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte s->cached_available_space = LESS_BY(MIN(m->max_use, avail), sum);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte char fb1[FORMAT_BYTES_MAX], fb2[FORMAT_BYTES_MAX], fb3[FORMAT_BYTES_MAX],
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte server_driver_message(s, SD_MESSAGE_JOURNAL_USAGE,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "%s journal is using %s (max allowed %s, "
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "trying to leave %s free of %s available → current limit %s).",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte format_bytes(fb5, sizeof(fb5), s->cached_available_space + sum));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortevoid server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte log_warning("Failed to fix access mode on %s, ignoring: %s", f->path, strerror(-r));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte log_warning("Failed to read ACL on %s, ignoring: %m", f->path);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (r <= 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte log_warning("Failed to patch ACL on %s, ignoring: %m", f->path);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* We do not recalculate the mask unconditionally here,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * so that the fchmod() mask above stays intact. */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte log_warning("Failed to patch ACL on %s, ignoring: %m", f->path);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte log_warning("Failed to set ACL on %s, ignoring: %m", f->path);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic JournalFile* find_journal(Server *s, uid_t uid) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* We split up user logs only on /var, not on /run. If the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * runtime file is open, we write to it exclusively, in order
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * to guarantee proper order as soon as we flush /run to
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * /var and close the runtime file. */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte f = hashmap_get(s->user_journals, UINT32_TO_PTR(uid));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/user-"UID_FMT".journal",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte while (hashmap_size(s->user_journals) >= USER_JOURNALS_MAX) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Too many open? Then let's close one */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte r = journal_file_open_reliably(p, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &f);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte r = hashmap_put(s->user_journals, UINT32_TO_PTR(uid), f);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (r < 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int do_rotate(Server *s, JournalFile **f, const char* name,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte do_rotate(s, &s->runtime_journal, "runtime", false, 0);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte do_rotate(s, &s->system_journal, "system", s->seal, 0);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte r = do_rotate(s, &f, "user", s->seal, PTR_TO_UINT32(k));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte else if (!f)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Old file has been closed and deallocated */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte log_error("Failed to sync system journal: %s", strerror(-r));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte log_error("Failed to sync user journal: %s", strerror(-r));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte r = sd_event_source_set_enabled(s->sync_event_source, SD_EVENT_OFF);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte log_error("Failed to disable sync timer source: %s", strerror(-r));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic void do_vacuum(Server *s, char *ids, JournalFile *f, const char* path,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte r = journal_directory_vacuum(p, metrics->max_use, s->max_retention_usec, &s->oldest_file_usec);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (r < 0 && r != -ENOENT)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte log_error("Failed to vacuum %s: %s", p, strerror(-r));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (r < 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte log_error("Failed to get machine ID: %s", strerror(-r));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte do_vacuum(s, ids, s->system_journal, "/var/log/journal/", &s->system_metrics);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte do_vacuum(s, ids, s->runtime_journal, "/run/log/journal/", &s->runtime_metrics);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sd_id128_to_string(id, stpcpy(s->machine_id_field, "_MACHINE_ID="));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sd_id128_to_string(id, stpcpy(s->boot_id_field, "_BOOT_ID="));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortebool shall_try_append_again(JournalFile *f, int r) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* -E2BIG Hit configured limit
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte -EFBIG Hit fs limit
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte -EDQUOT Quota limit hit
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte -ENOSPC Disk full
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte -EHOSTDOWN Other machine
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte -EBUSY Unclean shutdown
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte -EPROTONOSUPPORT Unsupported feature
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte -EBADMSG Corrupted
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte -ENODATA Truncated
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte -ESHUTDOWN Already archived */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (r == -E2BIG || r == -EFBIG || r == -EDQUOT || r == -ENOSPC)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte log_debug("%s: Allocation limit reached, rotating.", f->path);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte else if (r == -EHOSTDOWN)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte log_info("%s: Journal file from other machine, rotating.", f->path);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte else if (r == -EBUSY)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte log_info("%s: Unclean shutdown, rotating.", f->path);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte else if (r == -EPROTONOSUPPORT)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte log_info("%s: Unsupported feature, rotating.", f->path);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte else if (r == -EBADMSG || r == -ENODATA || r == ESHUTDOWN)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte log_warning("%s: Journal file corrupted, rotating.", f->path);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return false;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return true;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned n, int priority) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte bool vacuumed = false;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (journal_file_rotate_suggested(f, s->max_file_usec)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte log_debug("%s: Journal header limits reached or header out-of-date, rotating.", f->path);
server_rotate(s);
server_vacuum(s);
log_error("Failed to write entry (%d items, %zu bytes) despite vacuuming, ignoring: %s", n, size, strerror(-r));
static void dispatch_message_real(
Server *s,
const char *unit_id,
int priority,
bool owner_valid = false;
#ifdef HAVE_AUDIT
assert(s);
assert(n > 0);
if (ucred) {
free(t);
free(t);
free(t);
free(t);
#ifdef HAVE_AUDIT
r = cg_path_get_session(c, &t);
free(t);
owner_valid = true;
if (cg_path_get_unit(c, &t) >= 0) {
free(t);
if (cg_path_get_user_unit(c, &t) >= 0) {
free(t);
if (cg_path_get_slice(c, &t) >= 0) {
free(t);
free(c);
} else if (unit_id) {
#ifdef HAVE_SELINUX
if (use_selinux()) {
if (label) {
assert(n <= m);
if (object_pid) {
free(t);
free(t);
free(t);
#ifdef HAVE_AUDIT
r = cg_path_get_session(c, &t);
free(t);
if (cg_path_get_unit(c, &t) >= 0) {
free(t);
if (cg_path_get_user_unit(c, &t) >= 0) {
free(t);
free(c);
assert(n <= m);
if (tv) {
assert(n <= m);
journal_uid = 0;
assert(s);
void server_dispatch_message(
Server *s,
const char *unit_id,
int priority,
int rl, r;
assert(s);
if (!ucred)
goto finish;
goto finish;
if (rl == 0)
char *fn;
if (!s->system_journal &&
r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &s->system_journal);
if (!s->runtime_journal &&
if (!fn)
return -ENOMEM;
if (s->system_journal) {
r = journal_file_open(fn, O_RDWR, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
if (r != -ENOENT)
r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
if (s->runtime_journal)
available_space(s, true);
assert(s);
if (!s->runtime_journal)
if (!s->system_journal)
SD_JOURNAL_FOREACH(j) {
JournalFile *f;
f = j->current_file;
goto finish;
goto finish;
server_rotate(s);
server_vacuum(s);
if (!s->system_journal) {
r = -EIO;
goto finish;
goto finish;
sd_journal_close(j);
server_driver_message(s, SD_ID128_NULL, "Time spent on flushing to /var is %s for %u entries.", format_timespan(ts, sizeof(ts), now(CLOCK_MONOTONIC) - start, 0), n);
assert(s);
return -EIO;
} control = {};
ssize_t n;
unsigned n_fds = 0;
return -errno;
return log_oom();
return -errno;
if (n > 0 && n_fds == 0) {
s->buffer[n] = 0;
} else if (n_fds > 0)
if (n > 0 && n_fds == 0)
else if (n_fds > 0)
static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
assert(s);
server_sync(s);
server_vacuum(s);
static int dispatch_sigusr2(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
assert(s);
server_rotate(s);
server_vacuum(s);
static int dispatch_sigterm(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
assert(s);
assert(s);
const char *w, *state;
size_t l;
if (!word)
return -ENOMEM;
s->forward_to_syslog = r;
s->forward_to_kmsg = r;
s->forward_to_console = r;
s->forward_to_wall = r;
assert(s);
assert(s);
server_sync(s);
assert(s);
server_sync(s);
if (s->sync_scheduled)
if (s->sync_interval_usec > 0) {
if (!s->sync_event_source) {
r = sd_event_add_time(
s->event,
&s->sync_event_source,
when, 0,
server_dispatch_sync, s);
s->sync_scheduled = true;
static int dispatch_hostname_change(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
assert(s);
assert(s);
if (s->hostname_fd < 0) {
return -errno;
r = sd_event_add_io(s->event, &s->hostname_event_source, s->hostname_fd, 0, dispatch_hostname_change, s);
if (r == -EPERM) {
strerror(-r));
int n, r, fd;
assert(s);
zero(*s);
s->compress = true;
s->seal = true;
s->sync_scheduled = false;
s->forward_to_wall = true;
if (!s->user_journals)
return log_oom();
if (!s->mmap)
return log_oom();
n = sd_listen_fds(true);
if (s->native_fd >= 0) {
return -EINVAL;
if (s->stdout_fd >= 0) {
return -EINVAL;
if (s->syslog_fd >= 0) {
return -EINVAL;
return -EINVAL;
r = server_open_syslog_socket(s);
r = server_open_native_socket(s);
r = server_open_stdout_socket(s);
r = server_open_dev_kmsg(s);
r = server_open_kernel_seqnum(s);
r = server_open_hostname(s);
r = setup_signals(s);
if (!s->udev)
return -ENOMEM;
if (!s->rate_limit)
return -ENOMEM;
r = system_journal_open(s);
#ifdef HAVE_GCRYPT
JournalFile *f;
Iterator i;
usec_t n;
if (s->system_journal)
JournalFile *f;
assert(s);
while (s->stdout_streams)
if (s->system_journal)
if (s->runtime_journal)
if (s->rate_limit)
if (s->kernel_seqnum)
if (s->mmap)
if (s->udev)