journald.c revision 89fef99014662a5a63e7deaedd6292b7fb4ab2f8
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen This file is part of systemd.
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen Copyright 2011 Lennart Poettering
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen systemd is free software; you can redistribute it and/or modify it
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen under the terms of the GNU Lesser General Public License as published by
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen the Free Software Foundation; either version 2.1 of the License, or
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen (at your option) any later version.
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen systemd is distributed in the hope that it will be useful, but
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen WITHOUT ANY WARRANTY; without even the implied warranty of
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen Lesser General Public License for more details.
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen You should have received a copy of the GNU Lesser General Public License
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen#include <systemd/sd-journal.h>
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen#include <systemd/sd-messages.h>
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen#include <systemd/sd-daemon.h>
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen#include "journal-rate-limit.h"
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen#include "journal-authenticate.h"
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen#define USER_JOURNALS_MAX 1024
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen#define STDOUT_STREAMS_MAX 4096
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen#define DEFAULT_RATE_LIMIT_INTERVAL (10*USEC_PER_SEC)
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen#define DEFAULT_RATE_LIMIT_BURST 200
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen#define RECHECK_AVAILABLE_SPACE_USEC (30*USEC_PER_SEC)
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen#define N_IOVEC_META_FIELDS 17
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen#define N_IOVEC_KERNEL_FIELDS 64
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen#define ENTRY_SIZE_MAX (1024*1024*32)
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersentypedef enum StdoutStreamState {
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen STDOUT_STREAM_FORWARD_TO_SYSLOG,
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen STDOUT_STREAM_FORWARD_TO_KMSG,
97b5f608182773d7ef9ca18913085b3a3eccd943Thomas Hindoe Paaboel Andersen STDOUT_STREAM_FORWARD_TO_CONSOLE,
int fd;
#ifdef HAVE_SELINUX
char *identifier;
char *unit_id;
int priority;
static const char* const storage_table[] = {
DEFINE_CONFIG_PARSE_ENUM(config_parse_storage, storage, Storage, "Failed to parse storage setting");
DIR *d;
JournalMetrics *m;
return s->cached_available_space;
if (s->system_journal) {
m = &s->system_metrics;
m = &s->runtime_metrics;
assert(m);
d = opendir(p);
free(p);
goto finish;
if (!de)
closedir(d);
return avail;
assert(s);
if (s->file_gid_valid)
s->file_gid_valid = true;
#ifdef HAVE_ACL
assert(f);
#ifdef HAVE_ACL
if (uid <= 0)
if (!acl) {
goto finish;
goto finish;
JournalFile *f;
assert(s);
if (s->runtime_journal)
return s->runtime_journal;
if (uid <= 0)
return s->system_journal;
return s->system_journal;
return s->system_journal;
assert(f);
r = journal_file_open_reliably(p, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, s->system_journal, &f);
free(p);
return s->system_journal;
return s->system_journal;
JournalFile *f;
Iterator i;
if (s->runtime_journal) {
if (s->runtime_journal)
if (s->system_journal) {
if (s->system_journal)
if (f->path)
if (s->system_journal) {
log_oom();
if (r < 0 && r != -ENOENT)
free(p);
if (s->runtime_journal) {
log_oom();
if (r < 0 && r != -ENOENT)
free(p);
s->cached_available_space_timestamp = 0;
return NULL;
return NULL;
init_path[0] = 0;
return NULL;
path = p;
return path;
JournalFile *f;
bool vacuumed = false;
assert(s);
assert(n > 0);
if (journal_file_rotate_suggested(f)) {
server_rotate(s);
server_vacuum(s);
vacuumed = true;
if (vacuumed ||
else if (r == -EHOSTDOWN)
else if (r == -EBUSY)
server_rotate(s);
server_vacuum(s);
vacuumed = true;
static void dispatch_message_real(
Server *s,
const char *unit_id) {
assert(s);
assert(n > 0);
if (ucred) {
#ifdef HAVE_LOGIND
free(t);
if (comm)
free(t);
if (exe)
free(t);
if (cmdline)
free(t);
if (cgroup)
#ifdef HAVE_LOGIND
free(t);
if (session)
free(t);
} else if (unit_id)
if (unit)
#ifdef HAVE_SELINUX
if (label) {
if (selinux_context) {
if (selinux_context)
if (tv) {
t = gethostname_malloc();
free(t);
if (hostname)
assert(n <= m);
assert(s);
const char *unit_id,
int priority) {
int rl;
assert(s);
if (!ucred)
goto finish;
if (!path)
goto finish;
if (rl == 0) {
static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, struct ucred *ucred, struct timeval *tv) {
} control;
assert(s);
if (ucred) {
struct ucred u;
u = *ucred;
static void forward_syslog_raw(Server *s, int priority, const char *buffer, struct ucred *ucred, struct timeval *tv) {
assert(s);
static void forward_syslog(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred, struct timeval *tv) {
time_t t;
assert(s);
if (!tm)
if (ucred) {
if (!identifier) {
if (identifier)
} else if (identifier) {
return priority;
static void forward_kmsg(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred) {
assert(s);
if (ucred) {
if (!identifier) {
if (identifier)
} else if (identifier) {
static void forward_console(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred) {
int n = 0, fd;
const char *tty;
assert(s);
if (ucred) {
if (!identifier) {
if (identifier)
} else if (identifier) {
if (fd < 0) {
goto finish;
size_t l, e;
p = *buf;
*pid = t;
t = strndup(p, l);
*identifier = t;
*buf = p + e;
static void process_syslog_message(Server *s, const char *buf, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len) {
char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *syslog_pid = NULL;
const char *orig;
assert(s);
if (s->forward_to_syslog)
if (s->forward_to_kmsg)
if (s->forward_to_console)
if (identifier) {
if (syslog_identifier)
if (pid) {
if (syslog_pid)
if (message)
static void process_native_message(
Server *s,
assert(s);
p = buffer;
while (remaining > 0) {
remaining--;
if (n+N_IOVEC_META_FIELDS >= m) {
struct iovec *c;
log_oom();
iovec = c;
if (valid_user_field(p, q - p)) {
size_t l;
identifier = t;
message = t;
uint64_t l;
log_oom();
memcpy(k, p, e - p);
if (valid_user_field(p, e - p)) {
free(k);
goto finish;
tn = n++;
if (message) {
if (s->forward_to_syslog)
if (s->forward_to_kmsg)
if (s->forward_to_console)
if (j == tn)
static void process_native_file(
Server *s,
int fd,
ssize_t n;
assert(s);
log_oom();
free(p);
int priority;
assert(s);
assert(p);
if (isempty(p))
if (s->level_prefix)
if (s->identifier) {
if (syslog_identifier)
if (message)
#ifdef HAVE_SELINUX
if (s->security_context) {
dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority);
assert(s);
assert(p);
p = strstrip(p);
switch (s->state) {
case STDOUT_STREAM_IDENTIFIER:
if (isempty(p))
if (!s->identifier)
return log_oom();
case STDOUT_STREAM_UNIT_ID:
if (isempty(p))
if (!s->unit_id)
return log_oom();
case STDOUT_STREAM_PRIORITY:
return -EINVAL;
r = parse_boolean(p);
return -EINVAL;
s->level_prefix = !!r;
r = parse_boolean(p);
return -EINVAL;
s->forward_to_syslog = !!r;
r = parse_boolean(p);
return -EINVAL;
s->forward_to_kmsg = !!r;
r = parse_boolean(p);
return -EINVAL;
s->forward_to_console = !!r;
case STDOUT_STREAM_RUNNING:
return stdout_stream_log(s, p);
assert(s);
p = s->buffer;
char *end;
if (end)
*end = 0;
r = stdout_stream_line(s, p);
p += skip;
p[remaining] = 0;
r = stdout_stream_line(s, p);
p += remaining;
remaining = 0;
if (p > s->buffer) {
ssize_t l;
assert(s);
return -errno;
r = stdout_stream_scan(s, true);
s->length += l;
r = stdout_stream_scan(s, false);
assert(s);
if (s->server) {
if (s->fd >= 0) {
if (s->server)
#ifdef HAVE_SELINUX
if (s->security_context)
free(s);
int fd, r;
assert(s);
if (fd < 0) {
return -errno;
if (!stream) {
return log_oom();
r = -errno;
goto fail;
#ifdef HAVE_SELINUX
r = -errno;
goto fail;
r = -errno;
goto fail;
s->n_stdout_streams ++;
fail:
pid_t t;
return t == getpid();
char *message = NULL, *syslog_priority = NULL, *syslog_pid = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *source_time = NULL;
int priority, r;
assert(s);
assert(p);
if (s->kernel_seqnum) {
driver_message(s, SD_MESSAGE_JOURNAL_MISSED, "Missed %llu kernel messages", (unsigned long long) serial - *s->kernel_seqnum - 1);
pl = e - p;
for (j = 0; l > 0 && j < N_IOVEC_KERNEL_FIELDS; j++) {
(unsigned long long) usec) >= 0)
goto finish;
if (identifier) {
if (syslog_identifier)
if (pid) {
if (syslog_pid)
if (message)
char *fn;
if (!s->system_journal &&
if (!fn)
return -ENOMEM;
if (!fn)
return -ENOMEM;
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)
sd_journal *j;
assert(s);
if (!s->runtime_journal)
if (!s->system_journal)
SD_JOURNAL_FOREACH(j) {
JournalFile *f;
f = j->current_file;
goto finish;
if (r == -E2BIG) {
server_rotate(s);
server_vacuum(s);
goto finish;
ssize_t l;
assert(s);
return -errno;
assert(s);
if (s->dev_kmsg_fd < 0)
if (!s->dev_kmsg_readable)
r = server_read_dev_kmsg(s);
assert(s);
ssize_t n;
return -EIO;
if (n != sizeof(sfsi)) {
return -EIO;
return -errno;
server_rotate(s);
server_vacuum(s);
return -EIO;
r = server_read_dev_kmsg(s);
return -EIO;
} control;
ssize_t n;
unsigned n_fds = 0;
return -errno;
size_t l;
return -ENOMEM;
s->buffer_size = l;
s->buffer = b;
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)
return -EIO;
return -EIO;
int one, r;
assert(s);
if (s->syslog_fd < 0) {
if (s->syslog_fd < 0) {
return -errno;
r = bind(s->syslog_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
return -errno;
return -errno;
#ifdef HAVE_SELINUX
return -errno;
return -errno;
int one, r;
assert(s);
if (s->native_fd < 0) {
if (s->native_fd < 0) {
return -errno;
r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
return -errno;
return -errno;
#ifdef HAVE_SELINUX
return -errno;
return -errno;
assert(s);
if (s->stdout_fd < 0) {
if (s->stdout_fd < 0) {
return -errno;
r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
return -errno;
return -errno;
return -errno;
assert(s);
if (s->dev_kmsg_fd < 0) {
return -errno;
s->dev_kmsg_readable = true;
int fd;
uint64_t *p;
assert(s);
fd = open("/run/systemd/journal/kernel-seqnum", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
if (fd < 0) {
if (p == MAP_FAILED) {
s->kernel_seqnum = p;
assert(s);
if (s->signal_fd < 0) {
return -errno;
return -errno;
size_t l;
char *word;
if (!word) {
r = -ENOMEM;
goto finish;
s->forward_to_syslog = r;
s->forward_to_kmsg = r;
s->forward_to_console = r;
FILE *f;
const char *fn;
assert(s);
return -errno;
r = config_parse(fn, f, "Journal\0", config_item_perf_lookup, (void*) journald_gperf_lookup, false, s);
fclose(f);
int n, r, fd;
assert(s);
zero(*s);
s->compress = true;
s->seal = true;
s->forward_to_syslog = true;
if (!s->user_journals)
return log_oom();
if (!s->mmap)
return log_oom();
if (s->epoll_fd < 0) {
return -errno;
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 = open_syslog_socket(s);
r = open_native_socket(s);
r = open_stdout_socket(s);
r = open_dev_kmsg(s);
r = open_kernel_seqnum(s);
r = open_signalfd(s);
if (!s->rate_limit)
return -ENOMEM;
r = system_journal_open(s);
JournalFile *f;
assert(s);
while (s->stdout_streams)
if (s->system_journal)
if (s->runtime_journal)
if (s->epoll_fd >= 0)
if (s->signal_fd >= 0)
if (s->syslog_fd >= 0)
if (s->native_fd >= 0)
if (s->stdout_fd >= 0)
if (s->dev_kmsg_fd >= 0)
if (s->rate_limit)
if (s->kernel_seqnum)
if (s->mmap)
return EXIT_FAILURE;
log_open();
goto finish;
sd_notify(false,
#ifdef HAVE_GCRYPT
usec_t u;
usec_t n;
r = -errno;
goto finish;
goto finish;
#ifdef HAVE_GCRYPT
sd_notify(false,