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
2012-04-12 02:20:58 +04:00
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
2010-02-03 15:03:47 +03:00
( 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
2012-04-12 02:20:58 +04:00
Lesser General Public License for more details .
2010-02-03 15:03:47 +03:00
2012-04-12 02:20:58 +04:00
You should have received a copy of the GNU Lesser General Public License
2010-02-03 15:03:47 +03:00
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>
2012-09-25 01:22:19 +04:00
# include <printf.h>
2010-01-20 21:18:52 +03:00
# include "log.h"
2010-04-06 23:57:45 +04:00
# include "util.h"
2012-09-17 02:21:25 +04:00
# include "missing.h"
2010-04-06 23:57:45 +04:00
# 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-27 21:57:37 +04:00
# define SNDBUF_SIZE (8*1024*1024)
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 ;
2012-04-03 21:25:29 +04:00
static int log_facility = LOG_DAEMON ;
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 ) ;
2012-09-18 00:14:24 +04:00
if ( console_fd < 0 )
2010-05-15 19:25:08 +04:00
return console_fd ;
} 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 ) ;
2012-09-18 00:14:24 +04:00
if ( kmsg_fd < 0 )
2010-04-06 23:57:45 +04:00
return - errno ;
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 ) {
int fd ;
2012-01-27 21:14:06 +04:00
/* All output to the syslog/journal fds we do asynchronously,
* and if the buffers are full we just drop the messages */
2012-01-12 07:34:31 +04:00
2012-01-27 21:14:06 +04:00
fd = socket ( AF_UNIX , type | SOCK_CLOEXEC | SOCK_NONBLOCK , 0 ) ;
2012-01-12 07:34:31 +04:00
if ( fd < 0 )
2010-09-08 05:07:44 +04:00
return - errno ;
2012-01-27 21:57:37 +04:00
fd_inc_sndbuf ( fd , SNDBUF_SIZE ) ;
2010-09-08 05:07:44 +04:00
return fd ;
}
2010-05-15 19:25:08 +04:00
static int log_open_syslog ( void ) {
2010-04-06 23:57:45 +04:00
int r ;
2013-03-25 03:59:00 +04:00
union sockaddr_union sa = {
. un . sun_family = AF_UNIX ,
. un . sun_path = " /dev/log " ,
} ;
2010-04-06 23:57:45 +04:00
if ( syslog_fd > = 0 )
return 0 ;
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
}
2012-04-03 21:24:12 +04:00
if ( connect ( syslog_fd , & sa . sa , offsetof ( struct sockaddr_un , sun_path ) + strlen ( sa . un . sun_path ) ) < 0 ) {
2010-09-08 05:07:44 +04:00
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 ;
}
2012-04-03 21:24:12 +04:00
if ( connect ( syslog_fd , & sa . sa , offsetof ( struct sockaddr_un , sun_path ) + strlen ( sa . un . sun_path ) ) < 0 ) {
2010-09-08 05:07:44 +04:00
r = - errno ;
goto fail ;
}
syslog_is_stream = true ;
} else
syslog_is_stream = false ;
2010-04-06 23:57:45 +04:00
return 0 ;
2010-05-15 19:25:08 +04:00
fail :
log_close_syslog ( ) ;
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 ) {
2013-03-25 03:59:00 +04:00
union sockaddr_union sa = {
. un . sun_family = AF_UNIX ,
. un . sun_path = " /run/systemd/journal/socket " ,
} ;
2012-01-12 07:34:31 +04:00
int r ;
if ( journal_fd > = 0 )
return 0 ;
journal_fd = create_log_socket ( SOCK_DGRAM ) ;
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 ;
}
return 0 ;
fail :
log_close_journal ( ) ;
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 ;
}
2012-05-23 00:00:37 +04:00
if ( ( log_target ! = LOG_TARGET_AUTO & & log_target ! = LOG_TARGET_SAFE ) | |
2010-11-12 03:01:04 +03:00
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-05-23 00:00:37 +04:00
log_target = = LOG_TARGET_SAFE | |
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 ;
}
2012-04-03 21:25:29 +04:00
void log_set_facility ( int facility ) {
log_facility = facility ;
}
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 ,
2013-01-05 20:59:46 +04:00
const char * object_name ,
const char * object ,
2011-04-07 20:48:50 +04:00
const char * buffer ) {
2010-01-20 21:18:52 +03:00
2010-05-15 19:25:08 +04:00
char location [ 64 ] ;
2013-03-25 03:59:00 +04:00
struct iovec iovec [ 5 ] = { } ;
2010-05-15 19:25:08 +04:00
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
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 ,
2013-01-05 20:59:46 +04:00
const char * object_name ,
const char * object ,
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 ] ;
2013-03-25 03:59:00 +04:00
struct iovec iovec [ 5 ] = { } ;
struct msghdr msghdr = {
. msg_iov = iovec ,
. msg_iovlen = ELEMENTSOF ( iovec ) ,
} ;
2010-04-06 23:57:45 +04:00
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 ) ;
2013-01-05 20:59:46 +04:00
tm = localtime ( & t ) ;
if ( ! tm )
2010-04-06 23:57:45 +04:00
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 ) ;
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 + + ;
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 ,
2013-01-05 20:59:46 +04:00
const char * object_name ,
const char * object ,
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 ] ;
2013-03-25 03:59:00 +04:00
struct iovec iovec [ 5 ] = { } ;
2010-04-06 23:57:45 +04:00
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 ) ;
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-11-26 19:39:46 +04:00
static int log_do_header ( char * header , size_t size ,
int level ,
const char * file , int line , const char * func ,
const char * object_name , const char * object ) {
snprintf ( header , size ,
2012-01-12 07:34:31 +04:00
" PRIORITY=%i \n "
2012-04-03 21:25:29 +04:00
" SYSLOG_FACILITY=%i \n "
2012-11-26 19:39:46 +04:00
" %s%.*s%s "
" %s%.*i%s "
" %s%.*s%s "
2013-01-05 20:59:46 +04:00
" %s%.*s%s "
2012-11-26 19:39:46 +04:00
" SYSLOG_IDENTIFIER=%s \n " ,
2012-01-12 07:34:31 +04:00
LOG_PRI ( level ) ,
2012-04-03 21:25:29 +04:00
LOG_FAC ( level ) ,
2012-11-26 19:39:46 +04:00
file ? " CODE_FILE= " : " " ,
file ? LINE_MAX : 0 , file , /* %.0s means no output */
file ? " \n " : " " ,
line ? " CODE_LINE= " : " " ,
line ? 1 : 0 , line , /* %.0d means no output too, special case for 0 */
line ? " \n " : " " ,
func ? " CODE_FUNCTION= " : " " ,
func ? LINE_MAX : 0 , func ,
func ? " \n " : " " ,
2013-01-05 20:59:46 +04:00
object ? object_name : " " ,
object ? LINE_MAX : 0 , object , /* %.0s means no output */
object ? " \n " : " " ,
2012-04-22 03:01:54 +04:00
program_invocation_short_name ) ;
2012-11-26 19:39:46 +04:00
header [ size - 1 ] = ' \0 ' ;
return 0 ;
}
2012-01-12 07:34:31 +04:00
2012-11-26 19:39:46 +04:00
static int write_to_journal (
int level ,
const char * file ,
int line ,
const char * func ,
const char * object_name ,
const char * object ,
const char * buffer ) {
char header [ LINE_MAX ] ;
2013-03-25 03:59:00 +04:00
struct iovec iovec [ 4 ] = { } ;
struct msghdr mh = { } ;
2012-11-26 19:39:46 +04:00
if ( journal_fd < 0 )
return 0 ;
log_do_header ( header , sizeof ( header ) , level ,
file , line , func , object_name , object ) ;
2012-01-12 07:34:31 +04:00
IOVEC_SET_STRING ( iovec [ 0 ] , header ) ;
2012-11-26 19:39:46 +04:00
IOVEC_SET_STRING ( iovec [ 1 ] , " MESSAGE= " ) ;
IOVEC_SET_STRING ( iovec [ 2 ] , buffer ) ;
IOVEC_SET_STRING ( iovec [ 3 ] , " \n " ) ;
2012-01-12 07:34:31 +04:00
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 ,
2013-01-05 20:59:46 +04:00
const char * object_name ,
const char * object ,
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 )
2012-04-03 21:25:29 +04:00
level = log_facility | 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 ) {
2013-01-05 20:59:46 +04:00
k = write_to_journal ( level , file , line , func ,
object_name , object , buffer ) ;
2013-02-27 17:33:50 +04:00
if ( k < 0 ) {
if ( k ! = - EAGAIN )
2012-01-12 07:34:31 +04:00
log_close_journal ( ) ;
log_open_kmsg ( ) ;
2013-02-27 17:33:50 +04:00
} else if ( k > 0 )
2012-01-12 07:34:31 +04:00
r + + ;
}
if ( log_target = = LOG_TARGET_SYSLOG_OR_KMSG | |
2010-05-21 05:31:49 +04:00
log_target = = LOG_TARGET_SYSLOG ) {
2013-01-05 20:59:46 +04:00
k = write_to_syslog ( level , file , line , func ,
object_name , object , buffer ) ;
2013-02-27 17:33:50 +04:00
if ( k < 0 ) {
if ( k ! = - EAGAIN )
2011-12-18 17:57:54 +04:00
log_close_syslog ( ) ;
2010-05-21 05:31:49 +04:00
log_open_kmsg ( ) ;
2013-02-27 17:33:50 +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 | |
2012-05-23 00:00:37 +04:00
log_target = = LOG_TARGET_SAFE | |
2010-11-12 03:01:04 +03:00
log_target = = LOG_TARGET_SYSLOG_OR_KMSG | |
2012-04-20 14:39:36 +04:00
log_target = = LOG_TARGET_JOURNAL_OR_KMSG | |
2010-08-17 05:31:45 +04:00
log_target = = LOG_TARGET_KMSG ) ) {
2010-05-21 05:31:49 +04:00
2013-01-05 20:59:46 +04:00
k = write_to_kmsg ( level , file , line , func ,
object_name , object , buffer ) ;
2013-02-27 17:33:50 +04:00
if ( k < 0 ) {
log_close_kmsg ( ) ;
2010-05-21 05:31:49 +04:00
log_open_console ( ) ;
2013-02-27 17:33:50 +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 ) {
2013-01-05 20:59:46 +04:00
k = write_to_console ( level , file , line , func ,
object_name , object , buffer ) ;
2011-12-18 17:57:54 +04:00
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 ) {
2013-04-02 18:31:55 +04:00
PROTECT_ERRNO ;
2010-06-04 21:45:53 +04:00
/* This modifies the buffer... */
if ( _likely_ ( LOG_PRI ( level ) > log_max_level ) )
return 0 ;
2013-04-02 18:31:55 +04:00
return log_dispatch ( level , file , line , func , NULL , NULL , buffer ) ;
2010-06-04 21:45:53 +04:00
}
2012-03-14 17:54:41 +04:00
int log_metav (
2010-04-06 23:57:45 +04:00
int level ,
const char * file ,
int line ,
const char * func ,
2012-03-14 17:54:41 +04:00
const char * format ,
va_list ap ) {
2010-04-06 23:57:45 +04:00
2013-04-02 18:31:55 +04:00
PROTECT_ERRNO ;
2010-08-21 05:57:47 +04:00
char buffer [ LINE_MAX ] ;
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
2010-05-15 19:25:08 +04:00
vsnprintf ( buffer , sizeof ( buffer ) , format , ap ) ;
char_array_0 ( buffer ) ;
2013-04-02 18:31:55 +04:00
return log_dispatch ( level , file , line , func , NULL , NULL , buffer ) ;
2010-04-22 05:51:26 +04:00
}
2010-04-06 23:57:45 +04:00
2012-03-14 17:54:41 +04:00
int log_meta (
int level ,
const char * file ,
int line ,
const char * func ,
const char * format , . . . ) {
int r ;
va_list ap ;
va_start ( ap , format ) ;
r = log_metav ( level , file , line , func , format , ap ) ;
va_end ( ap ) ;
return r ;
}
2013-01-05 20:59:46 +04:00
int log_metav_object (
int level ,
const char * file ,
int line ,
const char * func ,
const char * object_name ,
const char * object ,
const char * format ,
va_list ap ) {
2013-04-02 18:31:55 +04:00
PROTECT_ERRNO ;
2013-01-05 20:59:46 +04:00
char buffer [ LINE_MAX ] ;
if ( _likely_ ( LOG_PRI ( level ) > log_max_level ) )
return 0 ;
vsnprintf ( buffer , sizeof ( buffer ) , format , ap ) ;
char_array_0 ( buffer ) ;
2013-04-02 18:31:55 +04:00
return log_dispatch ( level , file , line , func ,
object_name , object , buffer ) ;
2013-01-05 20:59:46 +04:00
}
int log_meta_object (
int level ,
const char * file ,
int line ,
const char * func ,
const char * object_name ,
const char * object ,
const char * format , . . . ) {
int r ;
va_list ap ;
va_start ( ap , format ) ;
r = log_metav_object ( level , file , line , func ,
object_name , object , format , ap ) ;
va_end ( ap ) ;
return r ;
}
2012-01-19 16:00:34 +04:00
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
2012-01-17 15:05:33 +04:00
_noreturn_ static void log_assert ( const char * text , 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-04-22 05:51:26 +04:00
2012-01-17 15:05:33 +04:00
snprintf ( buffer , sizeof ( buffer ) , format , text , file , line , func ) ;
2010-04-22 05:51:26 +04:00
char_array_0 ( buffer ) ;
log_abort_msg = buffer ;
2013-01-05 20:59:46 +04:00
log_dispatch ( LOG_CRIT , file , line , func , NULL , NULL , buffer ) ;
2010-04-22 05:51:26 +04:00
abort ( ) ;
2010-01-20 21:18:52 +03:00
}
2012-01-19 16:00:34 +04:00
# pragma GCC diagnostic pop
2010-04-07 01:38:32 +04:00
2012-02-29 17:42:49 +04:00
_noreturn_ void log_assert_failed ( const char * text , const char * file , int line , const char * func ) {
2012-01-17 15:05:33 +04:00
log_assert ( text , file , line , func , " Assertion '%s' failed at %s:%u, function %s(). Aborting. " ) ;
}
2012-02-29 17:42:49 +04:00
_noreturn_ void log_assert_failed_unreachable ( const char * text , const char * file , int line , const char * func ) {
2012-01-17 15:05:33 +04:00
log_assert ( text , file , line , func , " Code should not be reached '%s' at %s:%u, function %s(). Aborting. " ) ;
}
2012-08-25 00:21:20 +04:00
int log_oom_internal ( const char * file , int line , const char * func ) {
2012-07-26 16:23:49 +04:00
log_meta ( LOG_ERR , file , line , func , " Out of memory. " ) ;
return - ENOMEM ;
}
2012-08-25 00:21:20 +04:00
int log_struct_internal (
int level ,
const char * file ,
int line ,
const char * func ,
const char * format , . . . ) {
2013-04-02 18:31:55 +04:00
PROTECT_ERRNO ;
2012-08-25 00:21:20 +04:00
va_list ap ;
int r ;
if ( _likely_ ( LOG_PRI ( level ) > log_max_level ) )
return 0 ;
if ( log_target = = LOG_TARGET_NULL )
return 0 ;
if ( ( level & LOG_FACMASK ) = = 0 )
level = log_facility | LOG_PRI ( level ) ;
if ( ( log_target = = LOG_TARGET_AUTO | |
log_target = = LOG_TARGET_JOURNAL_OR_KMSG | |
log_target = = LOG_TARGET_JOURNAL ) & &
journal_fd > = 0 ) {
char header [ LINE_MAX ] ;
2013-03-25 03:59:00 +04:00
struct iovec iovec [ 17 ] = { } ;
2012-08-25 00:21:20 +04:00
unsigned n = 0 , i ;
2013-04-16 05:58:22 +04:00
struct msghdr mh = {
. msg_iov = iovec ,
} ;
2012-11-26 19:39:46 +04:00
static const char nl = ' \n ' ;
2012-08-25 00:21:20 +04:00
/* If the journal is available do structured logging */
2012-11-26 19:39:46 +04:00
log_do_header ( header , sizeof ( header ) , level ,
file , line , func , NULL , NULL ) ;
2012-08-25 00:21:20 +04:00
IOVEC_SET_STRING ( iovec [ n + + ] , header ) ;
va_start ( ap , format ) ;
while ( format & & n + 1 < ELEMENTSOF ( iovec ) ) {
char * buf ;
2012-09-25 01:22:19 +04:00
va_list aq ;
2012-08-25 00:21:20 +04:00
2012-09-25 01:22:19 +04:00
/* We need to copy the va_list structure,
* since vasprintf ( ) leaves it afterwards at
* an undefined location */
va_copy ( aq , ap ) ;
if ( vasprintf ( & buf , format , aq ) < 0 ) {
va_end ( aq ) ;
2012-08-25 00:21:20 +04:00
r = - ENOMEM ;
goto finish ;
}
2012-09-25 01:22:19 +04:00
va_end ( aq ) ;
/* Now, jump enough ahead, so that we point to
* the next format string */
VA_FORMAT_ADVANCE ( format , ap ) ;
2012-08-25 00:21:20 +04:00
IOVEC_SET_STRING ( iovec [ n + + ] , buf ) ;
iovec [ n ] . iov_base = ( char * ) & nl ;
iovec [ n ] . iov_len = 1 ;
n + + ;
format = va_arg ( ap , char * ) ;
}
mh . msg_iovlen = n ;
if ( sendmsg ( journal_fd , & mh , MSG_NOSIGNAL ) < 0 )
r = - errno ;
else
r = 1 ;
finish :
2012-09-21 12:22:46 +04:00
va_end ( ap ) ;
2012-08-25 00:21:20 +04:00
for ( i = 1 ; i < n ; i + = 2 )
free ( iovec [ i ] . iov_base ) ;
} else {
char buf [ LINE_MAX ] ;
bool found = false ;
/* Fallback if journal logging is not available */
va_start ( ap , format ) ;
while ( format ) {
2012-09-25 01:22:19 +04:00
va_list aq ;
2012-08-25 00:21:20 +04:00
2012-09-25 01:22:19 +04:00
va_copy ( aq , ap ) ;
vsnprintf ( buf , sizeof ( buf ) , format , aq ) ;
va_end ( aq ) ;
2012-08-25 00:21:20 +04:00
char_array_0 ( buf ) ;
if ( startswith ( buf , " MESSAGE= " ) ) {
found = true ;
break ;
}
2012-09-25 01:22:19 +04:00
VA_FORMAT_ADVANCE ( format , ap ) ;
2012-08-25 00:21:20 +04:00
format = va_arg ( ap , char * ) ;
}
va_end ( ap ) ;
if ( found )
2013-01-05 20:59:46 +04:00
r = log_dispatch ( level , file , line , func ,
NULL , NULL , buf + 8 ) ;
2012-08-25 00:21:20 +04:00
else
r = - EINVAL ;
}
return r ;
}
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 ;
2012-09-17 02:21:25 +04:00
e = secure_getenv ( " SYSTEMD_LOG_TARGET " ) ;
2012-08-23 20:47:01 +04:00
if ( e & & log_set_target_from_string ( e ) < 0 )
log_warning ( " Failed to parse log target %s. Ignoring. " , e ) ;
2010-04-07 01:38:32 +04:00
2012-09-17 02:21:25 +04:00
e = secure_getenv ( " SYSTEMD_LOG_LEVEL " ) ;
2012-08-23 20:47:01 +04:00
if ( e & & 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
2012-09-17 02:21:25 +04:00
e = secure_getenv ( " SYSTEMD_LOG_COLOR " ) ;
2012-08-23 20:47:01 +04:00
if ( e & & log_show_color_from_string ( e ) < 0 )
log_warning ( " Failed to parse bool %s. Ignoring. " , e ) ;
2010-06-18 00:52:55 +04:00
2012-09-17 02:21:25 +04:00
e = secure_getenv ( " SYSTEMD_LOG_LOCATION " ) ;
2012-08-23 20:47:01 +04:00
if ( e & & 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 ;
}
2012-08-25 00:43:33 +04:00
bool log_on_console ( void ) {
if ( log_target = = LOG_TARGET_CONSOLE )
return true ;
return syslog_fd < 0 & & kmsg_fd < 0 & & journal_fd < 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 " ,
2012-05-23 00:00:37 +04:00
[ LOG_TARGET_SAFE ] = " safe " ,
2012-01-12 07:34:31 +04:00
[ LOG_TARGET_NULL ] = " null "
2010-04-07 01:38:32 +04:00
} ;
DEFINE_STRING_TABLE_LOOKUP ( log_target , LogTarget ) ;