journald-server.c revision 15d91bff36c61d38df8edff258d1702a017a0e66
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt This file is part of systemd.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt Copyright 2011 Lennart Poettering
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt systemd is free software; you can redistribute it and/or modify it
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt under the terms of the GNU Lesser General Public License as published by
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt the Free Software Foundation; either version 2.1 of the License, or
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt (at your option) any later version.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt systemd is distributed in the hope that it will be useful, but
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt WITHOUT ANY WARRANTY; without even the implied warranty of
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt Lesser General Public License for more details.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt You should have received a copy of the GNU Lesser General Public License
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt along with systemd; If not, see <http://www.gnu.org/licenses/>.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#define DEFAULT_SYNC_INTERVAL_USEC (5*USEC_PER_MINUTE)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#define DEFAULT_RATE_LIMIT_INTERVAL (30*USEC_PER_SEC)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#define RECHECK_AVAILABLE_SPACE_USEC (30*USEC_PER_SEC)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic const char* const storage_table[_STORAGE_MAX] = {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik FlyktDEFINE_CONFIG_PARSE_ENUM(config_parse_storage, storage, Storage, "Failed to parse storage setting");
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic const char* const split_mode_table[_SPLIT_MAX] = {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik FlyktDEFINE_STRING_TABLE_LOOKUP(split_mode, SplitMode);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik FlyktDEFINE_CONFIG_PARSE_ENUM(config_parse_split_mode, split_mode, SplitMode, "Failed to parse split mode setting");
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic uint64_t available_space(Server *s, bool verbose) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt const char *f;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (s->cached_available_space_timestamp + RECHECK_AVAILABLE_SPACE_USEC > ts
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt p = strappend(f, sd_id128_to_string(machine, ids));
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt /* If we reached a high mark, we will always allow this much
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt * again, unless usage goes above max_use. This watermark
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt * value is cached so that we don't give up space on pressure,
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt * but hover below the maximum usage. */
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt s->cached_available_space = LESS_BY(MIN(m->max_use, avail), sum);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt char fb1[FORMAT_BYTES_MAX], fb2[FORMAT_BYTES_MAX], fb3[FORMAT_BYTES_MAX],
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt server_driver_message(s, SD_MESSAGE_JOURNAL_USAGE,
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt "%s is currently using %s.\n"
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt "Maximum allowed usage is set to %s.\n"
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt "Leaving at least %s free (of currently available %s of space).\n"
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt "Enforced usage limit is thus %s.",
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt s->system_journal ? "Permanent journal (/var/log/journal/)" : "Runtime journal (/run/log/journal/)",
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt format_bytes(fb5, sizeof(fb5), s->cached_available_space + sum));
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktvoid server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt log_warning_errno(r, "Failed to fix access mode on %s, ignoring: %m", f->path);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_warning_errno(errno, "Failed to read ACL on %s, ignoring: %m", f->path);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (r <= 0) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* We do not recalculate the mask unconditionally here,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * so that the fchmod() mask above stays intact. */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_warning_errno(errno, "Failed to set ACL on %s, ignoring: %m", f->path);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic JournalFile* find_journal(Server *s, uid_t uid) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* We split up user logs only on /var, not on /run. If the
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * runtime file is open, we write to it exclusively, in order
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * to guarantee proper order as soon as we flush /run to
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * /var and close the runtime file. */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt f = ordered_hashmap_get(s->user_journals, UINT32_TO_PTR(uid));
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/user-"UID_FMT".journal",
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt while (ordered_hashmap_size(s->user_journals) >= USER_JOURNALS_MAX) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* Too many open? Then let's close one */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt f = ordered_hashmap_steal_first(s->user_journals);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt r = journal_file_open_reliably(p, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &f);
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen r = ordered_hashmap_put(s->user_journals, UINT32_TO_PTR(uid), f);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt const char* name,
assert(s);
return -EINVAL;
JournalFile *f;
Iterator i;
JournalFile *f;
Iterator i;
if (s->system_journal) {
r = journal_file_set_offline(f);
if (s->sync_event_source) {
s->sync_scheduled = false;
static void do_vacuum(
Server *s,
const char *id,
JournalFile *f,
const char* path,
r = journal_directory_vacuum(p, metrics->max_use, s->max_retention_usec, &s->oldest_file_usec, false);
if (r < 0 && r != -ENOENT)
s->oldest_file_usec = 0;
s->cached_available_space_timestamp = 0;
assert(s);
assert(s);
assert(s);
t = gethostname_malloc();
s->hostname_field = x;
else if (r == -EHOSTDOWN)
else if (r == -EBUSY)
else if (r == -EPROTONOSUPPORT)
else if (r == -EIO)
else if (r == -EIDRM)
JournalFile *f;
bool vacuumed = false;
assert(s);
assert(n > 0);
server_rotate(s);
server_vacuum(s);
vacuumed = true;
log_error_errno(r, "Failed to write entry (%d items, %zu bytes), ignoring: %m", n, IOVEC_TOTAL_SIZE(iovec, n));
server_rotate(s);
server_vacuum(s);
log_error_errno(r, "Failed to write entry (%d items, %zu bytes) despite vacuuming, ignoring: %m", n, IOVEC_TOTAL_SIZE(iovec, n));
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 (mac_selinux_use()) {
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)
system_journal_open(s, true);
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);
ssize_t n;
unsigned n_fds = 0;
} control = {};
assert(s);
return -EIO;
return log_oom();
s->buffer[n] = 0;
if (n > 0 && n_fds == 0)
else if (n_fds > 0)
if (n > 0 && n_fds == 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)
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;
if (s->audit_fd >= 0) {
return -EINVAL;
if (!fds) {
if (!fds)
return log_oom();
return log_oom();
r = server_open_stdout_socket(s);
r = server_open_syslog_socket(s);
r = server_open_native_socket(s);
r = server_open_dev_kmsg(s);
r = server_open_audit(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, false);
#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)