log.c revision 158350e86923cb1d878d3bf7d928fb1c30a3da76
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier This file is part of systemd.
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier Copyright 2010 Lennart Poettering
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier systemd is free software; you can redistribute it and/or modify it
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier under the terms of the GNU Lesser General Public License as published by
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier the Free Software Foundation; either version 2.1 of the License, or
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier (at your option) any later version.
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier systemd is distributed in the hope that it will be useful, but
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier WITHOUT ANY WARRANTY; without even the implied warranty of
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier Lesser General Public License for more details.
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier You should have received a copy of the GNU Lesser General Public License
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier along with systemd; If not, see <http://www.gnu.org/licenses/>.
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalierstatic LogTarget log_target = LOG_TARGET_CONSOLE;
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalierstatic bool syslog_is_stream = false;
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalierstatic bool show_color = false;
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalierstatic bool show_location = false;
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalierstatic bool upgrade_syslog_to_journal = false;
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier/* Akin to glibc's __abort_msg; which is private and we hence cannot
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier * use here. */
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalierstatic int log_open_console(void) {
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalierstatic int log_open_kmsg(void) {
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier /* We need a blocking fd here since we'd otherwise lose
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier messages way too early. However, let's not hang forever in the
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier unlikely case of a deadlock. */
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier (void) setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalierstatic int log_open_syslog(void) {
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier /* Some legacy syslog systems still use stream
6160e473fc2c52ab7c06f1d884a8901d2a5b6b73Ronny Chevalier * sockets. They really shouldn't. But what can we
if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
r = -errno;
goto fail;
syslog_is_stream = true;
syslog_is_stream = false;
fail:
void log_close_journal(void) {
static int log_open_journal(void) {
if (journal_fd >= 0)
if (journal_fd < 0) {
r = journal_fd;
goto fail;
if (connect(journal_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
r = -errno;
goto fail;
fail:
int log_open(void) {
r = log_open_journal();
r = log_open_syslog();
r = log_open_kmsg();
return log_open_console();
if (upgrade_syslog_to_journal) {
void log_close(void) {
void log_forget_fds(void) {
static int write_to_console(
int level,
int error,
const char *file,
int line,
const char *func,
const char *object_field,
const char *object,
const char *buffer) {
bool highlight;
if (console_fd < 0)
if (show_location) {
if (highlight)
if (highlight)
if (console_fd < 0)
return -errno;
return -errno;
static int write_to_syslog(
int level,
int error,
const char *file,
int line,
const char *func,
const char *object_field,
const char *object,
const char *buffer) {
time_t t;
if (syslog_fd < 0)
if (!tm)
return -EINVAL;
return -EINVAL;
if (syslog_is_stream)
ssize_t n;
return -errno;
if (!syslog_is_stream ||
static int write_to_kmsg(
int level,
int error,
const char*file,
int line,
const char *func,
const char *object_field,
const char *object,
const char *buffer) {
if (kmsg_fd < 0)
return -errno;
static int log_do_header(
char *header,
int level,
int error,
static int write_to_journal(
int level,
int error,
const char*file,
int line,
const char *func,
const char *object_field,
const char *object,
const char *buffer) {
if (journal_fd < 0)
return -errno;
static int log_dispatch(
int level,
int error,
const char *file,
int line,
const char *func,
const char *object_field,
const char *object,
char *buffer) {
return -error;
if (error < 0)
if (buffer[0] == 0)
if (k != -EAGAIN)
if (k != -EAGAIN)
buffer = e;
} while (buffer);
return -error;
int log_dump_internal(
int level,
int error,
const char *file,
int line,
const char *func,
char *buffer) {
if (error < 0)
return -error;
int log_internalv(
int level,
int error,
const char*file,
int line,
const char *func,
const char *format,
if (error < 0)
return -error;
if (error != 0)
int log_internal(
int level,
int error,
const char*file,
int line,
const char *func,
const char *format, ...) {
int log_object_internalv(
int level,
int error,
const char*file,
int line,
const char *func,
const char *object_field,
const char *object,
const char *format,
if (error < 0)
return -error;
if (error != 0)
int log_object_internal(
int level,
int error,
const char*file,
int line,
const char *func,
const char *object_field,
const char *object,
const char *format, ...) {
static void log_assert(
int level,
const char *text,
const char *file,
int line,
const char *func,
const char *format) {
log_assert(LOG_CRIT, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
abort();
noreturn void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
log_assert(LOG_CRIT, text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
abort();
log_assert(LOG_DEBUG, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
return -ENOMEM;
int log_struct_internal(
int level,
int error,
const char *file,
int line,
const char *func,
const char *format, ...) {
bool found = false;
if (error < 0)
return -error;
return -error;
journal_fd >= 0) {
bool fallback = false;
if (error != 0)
fallback = true;
goto finish;
if (!fallback)
return -error;
while (format) {
if (error != 0)
found = true;
if (!found)
return -error;
int log_set_target_from_string(const char *e) {
LogTarget t;
t = log_target_from_string(e);
return -EINVAL;
log_set_target(t);
int log_set_max_level_from_string(const char *e) {
t = log_level_from_string(e);
void log_parse_environment(void) {
if (e && log_set_target_from_string(e) < 0)
if (e && log_set_max_level_from_string(e) < 0)
if (e && log_show_color_from_string(e) < 0)
if (e && log_show_location_from_string(e) < 0)
return log_target;
int log_get_max_level(void) {
return log_max_level;
void log_show_color(bool b) {
show_color = b;
bool log_get_show_color(void) {
return show_color;
void log_show_location(bool b) {
show_location = b;
bool log_get_show_location(void) {
return show_location;
int log_show_color_from_string(const char *e) {
t = parse_boolean(e);
log_show_color(t);
int log_show_location_from_string(const char *e) {
t = parse_boolean(e);
bool log_on_console(void) {
void log_set_upgrade_syslog_to_journal(bool b) {
int log_syntax_internal(
const char *unit,
int level,
const char *config_file,
unsigned config_line,
int error,
const char *file,
int line,
const char *func,
const char *format, ...) {
if (error < 0)
return -error;
return -error;
if (error != 0)
if (unit)
r = log_struct_internal(
NULL);
r = log_struct_internal(
NULL);