journald.c revision 51abe64c859c01ffad4f80840396ad9f6d5c9e62
91f9dcaf9270fe465525638cc08bd94590273349Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
91f9dcaf9270fe465525638cc08bd94590273349Lennart Poettering This file is part of systemd.
91f9dcaf9270fe465525638cc08bd94590273349Lennart Poettering Copyright 2011 Lennart Poettering
91f9dcaf9270fe465525638cc08bd94590273349Lennart Poettering systemd is free software; you can redistribute it and/or modify it
91f9dcaf9270fe465525638cc08bd94590273349Lennart Poettering under the terms of the GNU Lesser General Public License as published by
91f9dcaf9270fe465525638cc08bd94590273349Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
91f9dcaf9270fe465525638cc08bd94590273349Lennart Poettering (at your option) any later version.
91f9dcaf9270fe465525638cc08bd94590273349Lennart Poettering systemd is distributed in the hope that it will be useful, but
91f9dcaf9270fe465525638cc08bd94590273349Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
91f9dcaf9270fe465525638cc08bd94590273349Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
91f9dcaf9270fe465525638cc08bd94590273349Lennart Poettering Lesser General Public License for more details.
094062918c50cd5a34f7b6510fe206bf78d7cc58Lennart Poettering You should have received a copy of the GNU Lesser General Public License
f84aea434f2b014716ce9067f0af4db24a91a7c4Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <stddef.h>
#ifdef HAVE_LOGIND
#include "mkdir.h"
#include "hashmap.h"
#include "journal-file.h"
#include "socket-util.h"
#include "cgroup-util.h"
#include "list.h"
#include "journal-rate-limit.h"
#include "journal-internal.h"
#include "conf-parser.h"
#include "journald.h"
#include "virt.h"
#include "missing.h"
#ifdef HAVE_ACL
#include "acl-util.h"
#ifdef HAVE_SELINUX
typedef enum StdoutStreamState {
struct StdoutStream {
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;
if (asprintf(&p, "/var/log/journal/%s/user-%lu.journal", sd_id128_to_string(machine, ids), (unsigned long) uid) < 0)
return s->system_journal;
assert(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)
r = journal_file_rotate(&f);
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);
(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->system_metrics, NULL, &s->system_journal);
if (!s->runtime_journal &&
if (!fn)
return -ENOMEM;
if (s->system_journal) {
if (r != -ENOENT)
r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, &s->runtime_metrics, 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;
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->forward_to_syslog = true;
if (!s->user_journals)
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_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)
return EXIT_FAILURE;
log_open();
goto finish;
sd_notify(false,
r = -errno;
goto finish;
goto finish;
sd_notify(false,