log.c revision d7832d2c6e0ef5f2839a2296c1cc2fc85c7d9632
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering This file is part of systemd.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering Copyright 2010 Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering systemd is free software; you can redistribute it and/or modify it
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering under the terms of the GNU General Public License as published by
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering the Free Software Foundation; either version 2 of the License, or
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering (at your option) any later version.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering systemd is distributed in the hope that it will be useful, but
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering General Public License for more details.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering You should have received a copy of the GNU General Public License
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic LogTarget log_target = LOG_TARGET_CONSOLE;
3f9da416457c4265b8f1179516a32ad1a987ff7dLennart Poetteringstatic bool syslog_is_stream = false;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic bool show_color = false;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic bool show_location = false;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering/* Akin to glibc's __abort_msg; which is private and we hence cannot
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * use here. */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int log_open_console(void) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to open /dev/console for logging: %s", strerror(-console_fd));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_debug("Successfully opened /dev/console for logging.");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int log_open_kmsg(void) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack log_error("Failed to open /dev/kmsg for logging: %s", strerror(errno));
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack log_debug("Successfully opened /dev/kmsg for logging.");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* All output to the syslog/journal fds we do asynchronously,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * and if the buffers are full we just drop the messages */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fd = socket(AF_UNIX, type|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int log_open_syslog(void) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering syslog_fd = create_log_socket(SOCK_DGRAM);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Some legacy syslog systems still use stream
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * sockets. They really shouldn't. But what can we
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering syslog_fd = create_log_socket(SOCK_STREAM);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_debug("Successfully opened syslog for logging.");
3f9da416457c4265b8f1179516a32ad1a987ff7dLennart Poettering log_debug("Failed to open syslog for logging: %s", strerror(-r));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int log_open_journal(void) {
16ac401407959cbc62312e61c2dd76dbc3a0793bLennart Poettering journal_fd = create_log_socket(SOCK_DGRAM);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering strncpy(sa.un.sun_path, "/run/systemd/journal/socket", sizeof(sa.un.sun_path));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (connect(journal_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_debug("Successfully opened journal for logging.");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_debug("Failed to open journal for logging: %s", strerror(-r));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* If we don't use the console we close it here, to not get
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * killed by SAK. If we don't use syslog we close it here so
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * that we are not confused by somebody deleting the socket in
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * the fs. If we don't use /dev/kmsg we still keep it open,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * because there is no reason to close it. */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Get the real /dev/console if we are PID=1, hence reopen */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering console_fd = kmsg_fd = syslog_fd = journal_fd = -1;
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack const char *func,
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack const char *buffer) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering unsigned n = 0;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering highlight = LOG_PRI(level) <= LOG_ERR && show_color;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering snprintf(location, sizeof(location), "(%s:%u) ", file, line);
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering const char *buffer) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering char header_priority[16], header_time[64], header_pid[16];
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering snprintf(header_priority, sizeof(header_priority), "<%i>", level);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering const char *buffer) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering char header_priority[16], header_pid[16];
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering snprintf(header_priority, sizeof(header_priority), "<%i>", level);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering IOVEC_SET_STRING(iovec[0], header_priority);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering const char *buffer) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering "PRIORITY=%i\n"
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering "SYSLOG_FACILITY=%i\n"
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering "CODE_FILE=%s\n"
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering "CODE_LINE=%i\n"
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering "CODE_FUNCTION=%s\n"
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Patch in LOG_DAEMON facility if necessary */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering k = write_to_journal(level, file, line, func, buffer);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering } else if (k > 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering k = write_to_syslog(level, file, line, func, buffer);
2f671520ebade4877cbf6aca3572a5f8c4e1871dLennart Poettering } else if (k > 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering k = write_to_kmsg(level, file, line, func, buffer);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering } else if (k > 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering k = write_to_console(level, file, line, func, buffer);
54d76c92868838e17d6aad0a3bb0cc7a5b11e35fDaniel Mack const char *func,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* This modifies the buffer... */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (_likely_(LOG_PRI(level) > log_max_level))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = log_dispatch(level, file, line, func, buffer);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (_likely_(LOG_PRI(level) > log_max_level))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering vsnprintf(buffer, sizeof(buffer), format, ap);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = log_dispatch(level, file, line, func, buffer);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering const char *format, ...) {
_noreturn_ static void log_assert(const char *text, const char *file, int line, const char *func, const char *format) {
abort();
_noreturn_ void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
log_assert(text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
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 (log_set_target_from_string(e) < 0)
if (log_set_max_level_from_string(e) < 0)
if (log_show_color_from_string(e) < 0)
if (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;
void log_show_location(bool b) {
show_location = b;
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);
static const char *const log_target_table[] = {