2010-08-14 21:59:25 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2010-01-20 21:18:52 +03:00
2010-02-03 15:03:47 +03:00
/***
This file is part of systemd .
Copyright 2010 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
systemd is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
General Public License for more details .
You should have received a copy of the GNU General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
2010-01-20 21:18:52 +03:00
# include <stdarg.h>
# include <stdio.h>
2010-01-28 00:39:29 +03:00
# include <errno.h>
2010-04-06 23:57:45 +04:00
# include <unistd.h>
# include <fcntl.h>
# include <sys/socket.h>
# include <sys/un.h>
2012-01-12 07:34:31 +04:00
# include <stddef.h>
2010-01-20 21:18:52 +03:00
# include "log.h"
2010-04-06 23:57:45 +04:00
# include "util.h"
# include "macro.h"
2012-01-12 07:34:31 +04:00
# include "socket-util.h"
2010-01-20 21:18:52 +03:00
2012-01-12 07:34:31 +04:00
# define SOCKET_TIMEOUT_USEC (5*USEC_PER_SEC)
2010-04-06 23:57:45 +04:00
static LogTarget log_target = LOG_TARGET_CONSOLE ;
2010-06-18 00:52:55 +04:00
static int log_max_level = LOG_INFO ;
2010-04-06 23:57:45 +04:00
2010-05-15 19:25:08 +04:00
static int console_fd = STDERR_FILENO ;
2010-04-06 23:57:45 +04:00
static int syslog_fd = - 1 ;
static int kmsg_fd = - 1 ;
2012-01-12 07:34:31 +04:00
static int journal_fd = - 1 ;
2010-04-06 23:57:45 +04:00
2010-09-08 05:07:44 +04:00
static bool syslog_is_stream = false ;
2010-06-18 00:52:55 +04:00
static bool show_color = false ;
static bool show_location = false ;
2011-02-21 17:32:17 +03:00
/* Akin to glibc's __abort_msg; which is private and we hence cannot
2010-04-22 05:51:26 +04:00
* use here . */
static char * log_abort_msg = NULL ;
2010-05-15 19:25:08 +04:00
void log_close_console ( void ) {
if ( console_fd < 0 )
return ;
2010-04-06 23:57:45 +04:00
2010-05-18 07:10:52 +04:00
if ( getpid ( ) = = 1 ) {
if ( console_fd > = 3 )
close_nointr_nofail ( console_fd ) ;
2010-05-15 19:25:08 +04:00
console_fd = - 1 ;
2010-04-06 23:57:45 +04:00
}
}
2010-05-15 19:25:08 +04:00
static int log_open_console ( void ) {
2010-04-06 23:57:45 +04:00
2010-05-15 19:25:08 +04:00
if ( console_fd > = 0 )
2010-04-06 23:57:45 +04:00
return 0 ;
2010-05-15 19:25:08 +04:00
if ( getpid ( ) = = 1 ) {
2012-01-12 07:34:31 +04:00
console_fd = open_terminal ( " /dev/console " , O_WRONLY | O_NOCTTY | O_CLOEXEC ) ;
if ( console_fd < 0 ) {
2010-05-15 19:25:08 +04:00
log_error ( " Failed to open /dev/console for logging: %s " , strerror ( - console_fd ) ) ;
return console_fd ;
}
2011-02-21 17:32:17 +03:00
log_debug ( " Successfully opened /dev/console for logging. " ) ;
2010-05-15 19:25:08 +04:00
} else
console_fd = STDERR_FILENO ;
return 0 ;
}
void log_close_kmsg ( void ) {
if ( kmsg_fd < 0 )
return ;
close_nointr_nofail ( kmsg_fd ) ;
kmsg_fd = - 1 ;
}
static int log_open_kmsg ( void ) {
2010-04-06 23:57:45 +04:00
if ( kmsg_fd > = 0 )
return 0 ;
2012-01-05 06:25:10 +04:00
kmsg_fd = open ( " /dev/kmsg " , O_WRONLY | O_NOCTTY | O_CLOEXEC ) ;
if ( kmsg_fd < 0 ) {
2010-11-08 06:43:17 +03:00
log_error ( " Failed to open /dev/kmsg for logging: %s " , strerror ( errno ) ) ;
2010-04-06 23:57:45 +04:00
return - errno ;
2010-04-08 03:22:27 +04:00
}
2010-04-06 23:57:45 +04:00
2011-02-21 17:32:17 +03:00
log_debug ( " Successfully opened /dev/kmsg for logging. " ) ;
2010-04-08 02:58:03 +04:00
2010-04-06 23:57:45 +04:00
return 0 ;
}
void log_close_syslog ( void ) {
2010-05-15 19:25:08 +04:00
if ( syslog_fd < 0 )
return ;
close_nointr_nofail ( syslog_fd ) ;
syslog_fd = - 1 ;
2010-04-06 23:57:45 +04:00
}
2010-09-08 05:07:44 +04:00
static int create_log_socket ( int type ) {
struct timeval tv ;
int fd ;
2011-12-18 17:57:54 +04:00
if ( getpid ( ) = = 1 )
/* systemd should not block on syslog */
type | = SOCK_NONBLOCK ;
2012-01-12 07:34:31 +04:00
fd = socket ( AF_UNIX , type | SOCK_CLOEXEC , 0 ) ;
if ( fd < 0 )
2010-09-08 05:07:44 +04:00
return - errno ;
/* Make sure we don't block for more than 5s when talking to
* syslog */
2012-01-12 07:34:31 +04:00
timeval_store ( & tv , SOCKET_TIMEOUT_USEC ) ;
2010-09-08 05:07:44 +04:00
if ( setsockopt ( fd , SOL_SOCKET , SO_SNDTIMEO , & tv , sizeof ( tv ) ) < 0 ) {
close_nointr_nofail ( fd ) ;
return - errno ;
}
return fd ;
}
2010-05-15 19:25:08 +04:00
static int log_open_syslog ( void ) {
2012-01-12 07:34:31 +04:00
union sockaddr_union sa ;
2010-04-06 23:57:45 +04:00
int r ;
if ( syslog_fd > = 0 )
return 0 ;
zero ( sa ) ;
sa . un . sun_family = AF_UNIX ;
strncpy ( sa . un . sun_path , " /dev/log " , sizeof ( sa . un . sun_path ) ) ;
2012-01-12 07:34:31 +04:00
syslog_fd = create_log_socket ( SOCK_DGRAM ) ;
if ( syslog_fd < 0 ) {
r = syslog_fd ;
2010-05-15 19:25:08 +04:00
goto fail ;
2010-04-06 23:57:45 +04:00
}
2010-09-08 05:07:44 +04:00
if ( connect ( syslog_fd , & sa . sa , sizeof ( sa ) ) < 0 ) {
close_nointr_nofail ( syslog_fd ) ;
/* Some legacy syslog systems still use stream
* sockets . They really shouldn ' t . But what can we
* do . . . */
2012-01-12 07:34:31 +04:00
syslog_fd = create_log_socket ( SOCK_STREAM ) ;
if ( syslog_fd < 0 ) {
r = syslog_fd ;
2010-09-08 05:07:44 +04:00
goto fail ;
}
if ( connect ( syslog_fd , & sa . sa , sizeof ( sa ) ) < 0 ) {
r = - errno ;
goto fail ;
}
syslog_is_stream = true ;
} else
syslog_is_stream = false ;
2011-02-21 17:32:17 +03:00
log_debug ( " Successfully opened syslog for logging. " ) ;
2010-04-08 02:58:03 +04:00
2010-04-06 23:57:45 +04:00
return 0 ;
2010-05-15 19:25:08 +04:00
fail :
log_close_syslog ( ) ;
2010-11-08 06:43:17 +03:00
log_debug ( " Failed to open syslog for logging: %s " , strerror ( - r ) ) ;
2010-05-15 19:25:08 +04:00
return r ;
}
2012-01-12 07:34:31 +04:00
void log_close_journal ( void ) {
if ( journal_fd < 0 )
return ;
close_nointr_nofail ( journal_fd ) ;
journal_fd = - 1 ;
}
static int log_open_journal ( void ) {
union sockaddr_union sa ;
int r ;
if ( journal_fd > = 0 )
return 0 ;
journal_fd = create_log_socket ( SOCK_DGRAM ) ;
if ( journal_fd < 0 ) {
r = journal_fd ;
goto fail ;
}
zero ( sa ) ;
sa . un . sun_family = AF_UNIX ;
strncpy ( sa . un . sun_path , " /run/systemd/journal/socket " , sizeof ( sa . un . sun_path ) ) ;
if ( connect ( journal_fd , & sa . sa , offsetof ( struct sockaddr_un , sun_path ) + strlen ( sa . un . sun_path ) ) < 0 ) {
r = - errno ;
goto fail ;
}
log_debug ( " Successfully opened journal for logging. " ) ;
return 0 ;
fail :
log_close_journal ( ) ;
log_debug ( " Failed to open journal for logging: %s " , strerror ( - r ) ) ;
return r ;
}
2010-05-15 19:25:08 +04:00
int log_open ( void ) {
int r ;
/* If we don't use the console we close it here, to not get
* killed by SAK . If we don ' t use syslog we close it here so
* that we are not confused by somebody deleting the socket in
* the fs . If we don ' t use / dev / kmsg we still keep it open ,
* because there is no reason to close it . */
2010-06-09 17:37:37 +04:00
if ( log_target = = LOG_TARGET_NULL ) {
2012-01-12 07:34:31 +04:00
log_close_journal ( ) ;
2010-06-09 17:37:37 +04:00
log_close_syslog ( ) ;
log_close_console ( ) ;
return 0 ;
}
2010-11-12 03:01:04 +03:00
if ( log_target ! = LOG_TARGET_AUTO | |
getpid ( ) = = 1 | |
2010-11-12 03:02:03 +03:00
isatty ( STDERR_FILENO ) < = 0 ) {
2010-11-12 03:01:04 +03:00
if ( log_target = = LOG_TARGET_AUTO | |
2012-01-12 07:34:31 +04:00
log_target = = LOG_TARGET_JOURNAL_OR_KMSG | |
log_target = = LOG_TARGET_JOURNAL ) {
r = log_open_journal ( ) ;
if ( r > = 0 ) {
log_close_syslog ( ) ;
2010-11-12 03:01:04 +03:00
log_close_console ( ) ;
return r ;
}
2012-01-12 07:34:31 +04:00
}
if ( log_target = = LOG_TARGET_SYSLOG_OR_KMSG | |
log_target = = LOG_TARGET_SYSLOG ) {
r = log_open_syslog ( ) ;
if ( r > = 0 ) {
log_close_journal ( ) ;
log_close_console ( ) ;
return r ;
}
}
2010-11-12 03:01:04 +03:00
if ( log_target = = LOG_TARGET_AUTO | |
2012-01-12 07:34:31 +04:00
log_target = = LOG_TARGET_JOURNAL_OR_KMSG | |
2010-11-12 03:01:04 +03:00
log_target = = LOG_TARGET_SYSLOG_OR_KMSG | |
2012-01-12 07:34:31 +04:00
log_target = = LOG_TARGET_KMSG ) {
r = log_open_kmsg ( ) ;
if ( r > = 0 ) {
log_close_journal ( ) ;
2010-11-12 03:01:04 +03:00
log_close_syslog ( ) ;
log_close_console ( ) ;
return r ;
}
2012-01-12 07:34:31 +04:00
}
2010-11-12 03:01:04 +03:00
}
2010-05-15 19:25:08 +04:00
2012-01-12 07:34:31 +04:00
log_close_journal ( ) ;
2010-05-15 19:25:08 +04:00
log_close_syslog ( ) ;
2010-10-20 02:56:26 +04:00
/* Get the real /dev/console if we are PID=1, hence reopen */
log_close_console ( ) ;
2010-05-15 19:25:08 +04:00
return log_open_console ( ) ;
2010-04-06 23:57:45 +04:00
}
void log_set_target ( LogTarget target ) {
assert ( target > = 0 ) ;
assert ( target < _LOG_TARGET_MAX ) ;
log_target = target ;
}
2011-07-25 23:22:57 +04:00
void log_close ( void ) {
2012-01-12 07:34:31 +04:00
log_close_journal ( ) ;
2011-07-25 23:22:57 +04:00
log_close_syslog ( ) ;
2012-01-12 07:34:31 +04:00
log_close_kmsg ( ) ;
log_close_console ( ) ;
2011-07-25 23:22:57 +04:00
}
2011-11-17 02:45:01 +04:00
void log_forget_fds ( void ) {
2012-01-12 07:34:31 +04:00
console_fd = kmsg_fd = syslog_fd = journal_fd = - 1 ;
2011-11-17 02:45:01 +04:00
}
2010-04-06 23:57:45 +04:00
void log_set_max_level ( int level ) {
assert ( ( level & LOG_PRIMASK ) = = level ) ;
log_max_level = level ;
}
2010-05-15 19:25:08 +04:00
static int write_to_console (
2011-04-07 20:48:50 +04:00
int level ,
const char * file ,
int line ,
const char * func ,
const char * buffer ) {
2010-01-20 21:18:52 +03:00
2010-05-15 19:25:08 +04:00
char location [ 64 ] ;
struct iovec iovec [ 5 ] ;
unsigned n = 0 ;
bool highlight ;
2010-01-20 21:18:52 +03:00
2010-05-15 19:25:08 +04:00
if ( console_fd < 0 )
return 0 ;
2010-06-18 00:52:55 +04:00
highlight = LOG_PRI ( level ) < = LOG_ERR & & show_color ;
2010-05-15 19:25:08 +04:00
zero ( iovec ) ;
2012-01-05 06:25:10 +04:00
if ( show_location ) {
snprintf ( location , sizeof ( location ) , " (%s:%u) " , file , line ) ;
char_array_0 ( location ) ;
2010-06-18 00:52:55 +04:00
IOVEC_SET_STRING ( iovec [ n + + ] , location ) ;
2012-01-05 06:25:10 +04:00
}
2010-05-15 19:25:08 +04:00
if ( highlight )
2012-01-14 00:56:09 +04:00
IOVEC_SET_STRING ( iovec [ n + + ] , ANSI_HIGHLIGHT_RED_ON ) ;
2010-05-15 19:25:08 +04:00
IOVEC_SET_STRING ( iovec [ n + + ] , buffer ) ;
if ( highlight )
2010-07-05 04:40:39 +04:00
IOVEC_SET_STRING ( iovec [ n + + ] , ANSI_HIGHLIGHT_OFF ) ;
2010-05-15 19:25:08 +04:00
IOVEC_SET_STRING ( iovec [ n + + ] , " \n " ) ;
if ( writev ( console_fd , iovec , n ) < 0 )
return - errno ;
2010-01-20 21:18:52 +03:00
2010-05-15 19:25:08 +04:00
return 1 ;
2010-04-06 23:57:45 +04:00
}
2010-01-20 21:18:52 +03:00
2010-04-06 23:57:45 +04:00
static int write_to_syslog (
int level ,
const char * file ,
int line ,
const char * func ,
2010-05-15 19:25:08 +04:00
const char * buffer ) {
2010-04-06 23:57:45 +04:00
char header_priority [ 16 ] , header_time [ 64 ] , header_pid [ 16 ] ;
struct iovec iovec [ 5 ] ;
struct msghdr msghdr ;
time_t t ;
struct tm * tm ;
if ( syslog_fd < 0 )
2010-05-15 19:25:08 +04:00
return 0 ;
2010-04-06 23:57:45 +04:00
2011-03-31 21:49:04 +04:00
snprintf ( header_priority , sizeof ( header_priority ) , " <%i> " , level ) ;
2010-04-06 23:57:45 +04:00
char_array_0 ( header_priority ) ;
t = ( time_t ) ( now ( CLOCK_REALTIME ) / USEC_PER_SEC ) ;
if ( ! ( tm = localtime ( & t ) ) )
return - EINVAL ;
if ( strftime ( header_time , sizeof ( header_time ) , " %h %e %T " , tm ) < = 0 )
return - EINVAL ;
2010-06-19 06:35:52 +04:00
snprintf ( header_pid , sizeof ( header_pid ) , " [%lu]: " , ( unsigned long ) getpid ( ) ) ;
2010-04-06 23:57:45 +04:00
char_array_0 ( header_pid ) ;
zero ( iovec ) ;
IOVEC_SET_STRING ( iovec [ 0 ] , header_priority ) ;
IOVEC_SET_STRING ( iovec [ 1 ] , header_time ) ;
2010-06-16 23:54:17 +04:00
IOVEC_SET_STRING ( iovec [ 2 ] , program_invocation_short_name ) ;
2010-04-06 23:57:45 +04:00
IOVEC_SET_STRING ( iovec [ 3 ] , header_pid ) ;
IOVEC_SET_STRING ( iovec [ 4 ] , buffer ) ;
2010-09-29 17:13:04 +04:00
/* When using syslog via SOCK_STREAM separate the messages by NUL chars */
2010-09-08 05:07:44 +04:00
if ( syslog_is_stream )
iovec [ 4 ] . iov_len + + ;
2010-04-06 23:57:45 +04:00
zero ( msghdr ) ;
msghdr . msg_iov = iovec ;
msghdr . msg_iovlen = ELEMENTSOF ( iovec ) ;
2010-09-08 05:07:44 +04:00
for ( ; ; ) {
ssize_t n ;
2011-12-18 17:57:54 +04:00
n = sendmsg ( syslog_fd , & msghdr , MSG_NOSIGNAL ) ;
if ( n < 0 )
2010-09-08 05:07:44 +04:00
return - errno ;
if ( ! syslog_is_stream | |
( size_t ) n > = IOVEC_TOTAL_SIZE ( iovec , ELEMENTSOF ( iovec ) ) )
break ;
IOVEC_INCREMENT ( iovec , ELEMENTSOF ( iovec ) , n ) ;
}
2010-04-06 23:57:45 +04:00
2010-05-15 19:25:08 +04:00
return 1 ;
2010-04-06 23:57:45 +04:00
}
static int write_to_kmsg (
int level ,
const char * file ,
int line ,
const char * func ,
2010-05-15 19:25:08 +04:00
const char * buffer ) {
2010-04-06 23:57:45 +04:00
char header_priority [ 16 ] , header_pid [ 16 ] ;
struct iovec iovec [ 5 ] ;
if ( kmsg_fd < 0 )
2010-05-15 19:25:08 +04:00
return 0 ;
2010-04-06 23:57:45 +04:00
2011-03-31 21:49:04 +04:00
snprintf ( header_priority , sizeof ( header_priority ) , " <%i> " , level ) ;
2010-04-06 23:57:45 +04:00
char_array_0 ( header_priority ) ;
2010-06-19 06:35:52 +04:00
snprintf ( header_pid , sizeof ( header_pid ) , " [%lu]: " , ( unsigned long ) getpid ( ) ) ;
2010-04-06 23:57:45 +04:00
char_array_0 ( header_pid ) ;
zero ( iovec ) ;
IOVEC_SET_STRING ( iovec [ 0 ] , header_priority ) ;
2010-06-16 23:54:17 +04:00
IOVEC_SET_STRING ( iovec [ 1 ] , program_invocation_short_name ) ;
2010-04-06 23:57:45 +04:00
IOVEC_SET_STRING ( iovec [ 2 ] , header_pid ) ;
IOVEC_SET_STRING ( iovec [ 3 ] , buffer ) ;
2010-05-15 19:25:08 +04:00
IOVEC_SET_STRING ( iovec [ 4 ] , " \n " ) ;
2010-04-06 23:57:45 +04:00
if ( writev ( kmsg_fd , iovec , ELEMENTSOF ( iovec ) ) < 0 )
return - errno ;
2010-05-15 19:25:08 +04:00
return 1 ;
2010-04-06 23:57:45 +04:00
}
2012-01-12 07:34:31 +04:00
static int write_to_journal (
int level ,
const char * file ,
int line ,
const char * func ,
const char * buffer ) {
char header [ LINE_MAX ] ;
struct iovec iovec [ 3 ] ;
struct msghdr mh ;
if ( journal_fd < 0 )
return 0 ;
snprintf ( header , sizeof ( header ) ,
" PRIORITY=%i \n "
" CODE_FILE=%s \n "
" CODE_LINE=%i \n "
" CODE_FUNCTION=%s \n "
" MESSAGE= " ,
LOG_PRI ( level ) ,
file ,
line ,
func ) ;
char_array_0 ( header ) ;
zero ( iovec ) ;
IOVEC_SET_STRING ( iovec [ 0 ] , header ) ;
IOVEC_SET_STRING ( iovec [ 1 ] , buffer ) ;
IOVEC_SET_STRING ( iovec [ 2 ] , " \n " ) ;
zero ( mh ) ;
mh . msg_iov = iovec ;
mh . msg_iovlen = ELEMENTSOF ( iovec ) ;
if ( sendmsg ( journal_fd , & mh , MSG_NOSIGNAL ) < 0 )
return - errno ;
return 1 ;
}
2010-05-15 19:25:08 +04:00
static int log_dispatch (
int level ,
const char * file ,
int line ,
const char * func ,
2010-05-21 05:31:49 +04:00
char * buffer ) {
2010-05-15 19:25:08 +04:00
2010-05-21 05:31:49 +04:00
int r = 0 ;
2010-05-15 19:25:08 +04:00
2010-06-09 17:37:37 +04:00
if ( log_target = = LOG_TARGET_NULL )
return 0 ;
2011-03-31 21:49:04 +04:00
/* Patch in LOG_DAEMON facility if necessary */
2011-03-31 23:22:44 +04:00
if ( ( level & LOG_FACMASK ) = = 0 )
level = LOG_DAEMON | LOG_PRI ( level ) ;
2011-03-31 21:49:04 +04:00
2010-05-21 05:31:49 +04:00
do {
char * e ;
2010-08-17 05:31:45 +04:00
int k = 0 ;
2010-05-15 19:25:08 +04:00
2010-05-21 05:31:49 +04:00
buffer + = strspn ( buffer , NEWLINE ) ;
2010-05-15 19:25:08 +04:00
2010-05-21 05:31:49 +04:00
if ( buffer [ 0 ] = = 0 )
break ;
2010-05-15 19:25:08 +04:00
2010-05-21 05:31:49 +04:00
if ( ( e = strpbrk ( buffer , NEWLINE ) ) )
* ( e + + ) = 0 ;
2010-05-15 19:25:08 +04:00
2010-11-12 03:01:04 +03:00
if ( log_target = = LOG_TARGET_AUTO | |
2012-01-12 07:34:31 +04:00
log_target = = LOG_TARGET_JOURNAL_OR_KMSG | |
log_target = = LOG_TARGET_JOURNAL ) {
k = write_to_journal ( level , file , line , func , buffer ) ;
if ( k < 0 ) {
if ( k ! = - EAGAIN )
log_close_journal ( ) ;
log_open_kmsg ( ) ;
} else if ( k > 0 )
r + + ;
}
if ( log_target = = LOG_TARGET_SYSLOG_OR_KMSG | |
2010-05-21 05:31:49 +04:00
log_target = = LOG_TARGET_SYSLOG ) {
2011-12-18 17:57:54 +04:00
k = write_to_syslog ( level , file , line , func , buffer ) ;
if ( k < 0 ) {
if ( k ! = - EAGAIN )
log_close_syslog ( ) ;
2010-05-21 05:31:49 +04:00
log_open_kmsg ( ) ;
2010-08-17 05:31:45 +04:00
} else if ( k > 0 )
2010-05-21 05:31:49 +04:00
r + + ;
}
2010-08-17 05:31:45 +04:00
if ( k < = 0 & &
2010-11-12 03:01:04 +03:00
( log_target = = LOG_TARGET_AUTO | |
log_target = = LOG_TARGET_SYSLOG_OR_KMSG | |
2010-08-17 05:31:45 +04:00
log_target = = LOG_TARGET_KMSG ) ) {
2010-05-21 05:31:49 +04:00
2011-12-18 17:57:54 +04:00
k = write_to_kmsg ( level , file , line , func , buffer ) ;
if ( k < 0 ) {
2010-05-21 05:31:49 +04:00
log_close_kmsg ( ) ;
log_open_console ( ) ;
2010-08-17 05:31:45 +04:00
} else if ( k > 0 )
2010-05-21 05:31:49 +04:00
r + + ;
}
2011-12-18 17:57:54 +04:00
if ( k < = 0 ) {
k = write_to_console ( level , file , line , func , buffer ) ;
if ( k < 0 )
return k ;
}
2010-05-21 05:31:49 +04:00
buffer = e ;
} while ( buffer ) ;
return r ;
2010-05-15 19:25:08 +04:00
}
2010-06-04 21:45:53 +04:00
int log_dump_internal (
int level ,
const char * file ,
int line ,
const char * func ,
char * buffer ) {
int saved_errno , r ;
/* This modifies the buffer... */
if ( _likely_ ( LOG_PRI ( level ) > log_max_level ) )
return 0 ;
saved_errno = errno ;
r = log_dispatch ( level , file , line , func , buffer ) ;
errno = saved_errno ;
return r ;
}
2010-05-15 19:25:08 +04:00
int log_meta (
2010-04-06 23:57:45 +04:00
int level ,
const char * file ,
int line ,
const char * func ,
const char * format , . . . ) {
2010-08-21 05:57:47 +04:00
char buffer [ LINE_MAX ] ;
2010-05-15 19:25:08 +04:00
int saved_errno , r ;
va_list ap ;
2010-04-06 23:57:45 +04:00
2010-06-02 23:34:03 +04:00
if ( _likely_ ( LOG_PRI ( level ) > log_max_level ) )
2010-05-15 19:25:08 +04:00
return 0 ;
2010-04-06 23:57:45 +04:00
saved_errno = errno ;
2010-05-15 19:25:08 +04:00
va_start ( ap , format ) ;
vsnprintf ( buffer , sizeof ( buffer ) , format , ap ) ;
va_end ( ap ) ;
char_array_0 ( buffer ) ;
r = log_dispatch ( level , file , line , func , buffer ) ;
2010-04-22 05:51:26 +04:00
errno = saved_errno ;
2010-05-15 19:25:08 +04:00
return r ;
2010-04-22 05:51:26 +04:00
}
2010-04-06 23:57:45 +04:00
2010-04-22 05:51:26 +04:00
void log_assert (
const char * file ,
int line ,
const char * func ,
const char * format , . . . ) {
2010-08-21 05:57:47 +04:00
static char buffer [ LINE_MAX ] ;
2010-05-15 19:25:08 +04:00
va_list ap ;
2010-04-22 05:51:26 +04:00
va_start ( ap , format ) ;
vsnprintf ( buffer , sizeof ( buffer ) , format , ap ) ;
va_end ( ap ) ;
char_array_0 ( buffer ) ;
log_abort_msg = buffer ;
2010-05-15 19:25:08 +04:00
log_dispatch ( LOG_CRIT , file , line , func , buffer ) ;
2010-04-22 05:51:26 +04:00
abort ( ) ;
2010-01-20 21:18:52 +03:00
}
2010-04-07 01:38:32 +04:00
int log_set_target_from_string ( const char * e ) {
LogTarget t ;
2012-01-12 07:34:31 +04:00
t = log_target_from_string ( e ) ;
if ( t < 0 )
2010-04-07 01:38:32 +04:00
return - EINVAL ;
log_set_target ( t ) ;
return 0 ;
}
int log_set_max_level_from_string ( const char * e ) {
int t ;
2012-01-12 07:34:31 +04:00
t = log_level_from_string ( e ) ;
if ( t < 0 )
return t ;
2010-04-07 01:38:32 +04:00
log_set_max_level ( t ) ;
return 0 ;
}
void log_parse_environment ( void ) {
const char * e ;
if ( ( e = getenv ( " SYSTEMD_LOG_TARGET " ) ) )
if ( log_set_target_from_string ( e ) < 0 )
log_warning ( " Failed to parse log target %s. Ignoring. " , e ) ;
if ( ( e = getenv ( " SYSTEMD_LOG_LEVEL " ) ) )
if ( log_set_max_level_from_string ( e ) < 0 )
log_warning ( " Failed to parse log level %s. Ignoring. " , e ) ;
2010-06-18 00:52:55 +04:00
2010-06-24 05:07:06 +04:00
if ( ( e = getenv ( " SYSTEMD_LOG_COLOR " ) ) )
2010-06-18 00:52:55 +04:00
if ( log_show_color_from_string ( e ) < 0 )
log_warning ( " Failed to parse bool %s. Ignoring. " , e ) ;
2010-10-20 02:56:26 +04:00
if ( ( e = getenv ( " SYSTEMD_LOG_LOCATION " ) ) )
2010-06-18 00:52:55 +04:00
if ( log_show_location_from_string ( e ) < 0 )
log_warning ( " Failed to parse bool %s. Ignoring. " , e ) ;
2010-04-07 01:38:32 +04:00
}
2010-04-10 19:40:18 +04:00
LogTarget log_get_target ( void ) {
return log_target ;
}
int log_get_max_level ( void ) {
return log_max_level ;
}
2010-06-18 00:52:55 +04:00
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 ) {
int t ;
2012-01-12 07:34:31 +04:00
t = parse_boolean ( e ) ;
if ( t < 0 )
return t ;
2010-06-18 00:52:55 +04:00
log_show_color ( t ) ;
return 0 ;
}
int log_show_location_from_string ( const char * e ) {
int t ;
2012-01-12 07:34:31 +04:00
t = parse_boolean ( e ) ;
if ( t < 0 )
return t ;
2010-06-18 00:52:55 +04:00
log_show_location ( t ) ;
return 0 ;
}
2010-04-07 01:38:32 +04:00
static const char * const log_target_table [ ] = {
[ LOG_TARGET_CONSOLE ] = " console " ,
[ LOG_TARGET_KMSG ] = " kmsg " ,
2012-01-12 07:34:31 +04:00
[ LOG_TARGET_JOURNAL ] = " journal " ,
[ LOG_TARGET_JOURNAL_OR_KMSG ] = " journal-or-kmsg " ,
[ LOG_TARGET_SYSLOG ] = " syslog " ,
2010-05-15 19:25:08 +04:00
[ LOG_TARGET_SYSLOG_OR_KMSG ] = " syslog-or-kmsg " ,
2012-01-12 07:34:31 +04:00
[ LOG_TARGET_AUTO ] = " auto " ,
[ LOG_TARGET_NULL ] = " null "
2010-04-07 01:38:32 +04:00
} ;
DEFINE_STRING_TABLE_LOOKUP ( log_target , LogTarget ) ;