2001-08-21 16:56:08 +04:00
/*
2008-01-30 17:00:02 +03:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2007-08-21 00:55:30 +04:00
* Copyright ( C ) 2004 - 2007 Red Hat , Inc . All rights reserved .
2001-08-21 16:56:08 +04:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2 .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
2007-08-21 00:55:30 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2004-03-30 23:35:44 +04:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +04:00
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2001-08-21 16:56:08 +04:00
*/
2002-11-18 17:01:16 +03:00
# include "lib.h"
2003-07-05 02:34:56 +04:00
# include "device.h"
# include "memlock.h"
# include "lvm-string.h"
2007-07-24 21:48:08 +04:00
# include "lvm-file.h"
2006-05-12 23:16:48 +04:00
# include "defaults.h"
2009-11-30 20:17:11 +03:00
# include "config.h"
2002-11-18 17:01:16 +03:00
2001-08-21 16:56:08 +04:00
# include <stdarg.h>
# include <syslog.h>
2003-07-05 02:34:56 +04:00
static FILE * _log_file ;
static struct device _log_dev ;
static struct str_list _log_dev_alias ;
2001-08-21 16:56:08 +04:00
static int _syslog = 0 ;
2003-07-05 02:34:56 +04:00
static int _log_to_file = 0 ;
static int _log_direct = 0 ;
static int _log_while_suspended = 0 ;
2002-01-22 18:33:40 +03:00
static int _indent = 1 ;
2002-03-16 01:54:04 +03:00
static int _log_suppress = 0 ;
2002-01-22 18:33:40 +03:00
static char _msg_prefix [ 30 ] = " " ;
2003-07-05 02:34:56 +04:00
static int _already_logging = 0 ;
2009-11-30 20:17:11 +03:00
static int _abort_on_internal_errors = 0 ;
2001-08-21 16:56:08 +04:00
2004-03-26 17:47:14 +03:00
static lvm2_log_fn_t _lvm2_log_fn = NULL ;
2009-07-16 03:57:54 +04:00
static int _lvm_errno = 0 ;
static int _store_errmsg = 0 ;
static char * _lvm_errmsg = NULL ;
2011-03-30 16:53:04 +04:00
static size_t _lvm_errmsg_size = 0 ;
static size_t _lvm_errmsg_len = 0 ;
# define MAX_ERRMSG_LEN (512 * 1024) /* Max size of error buffer 512KB */
2009-07-16 03:57:54 +04:00
2004-03-26 17:47:14 +03:00
void init_log_fn ( lvm2_log_fn_t log_fn )
{
if ( log_fn )
_lvm2_log_fn = log_fn ;
else
_lvm2_log_fn = NULL ;
}
2003-07-05 02:34:56 +04:00
void init_log_file ( const char * log_file , int append )
2002-03-16 01:54:04 +03:00
{
2003-07-05 02:34:56 +04:00
const char * open_mode = append ? " a " : " w " ;
if ( ! ( _log_file = fopen ( log_file , open_mode ) ) ) {
log_sys_error ( " fopen " , log_file ) ;
return ;
}
_log_to_file = 1 ;
}
void init_log_direct ( const char * log_file , int append )
{
int open_flags = append ? 0 : O_TRUNC ;
2005-05-03 21:28:23 +04:00
dev_create_file ( log_file , & _log_dev , & _log_dev_alias , 1 ) ;
2003-07-05 02:34:56 +04:00
if ( ! dev_open_flags ( & _log_dev , O_RDWR | O_CREAT | open_flags , 1 , 0 ) )
return ;
_log_direct = 1 ;
}
void init_log_while_suspended ( int log_while_suspended )
{
_log_while_suspended = log_while_suspended ;
2001-08-21 16:56:08 +04:00
}
2002-03-16 01:54:04 +03:00
void init_syslog ( int facility )
{
2001-08-21 16:56:08 +04:00
openlog ( " lvm " , LOG_PID , facility ) ;
_syslog = 1 ;
}
2006-04-13 21:32:24 +04:00
int log_suppress ( int suppress )
2002-03-16 01:54:04 +03:00
{
2006-04-13 21:32:24 +04:00
int old_suppress = _log_suppress ;
2002-03-16 01:54:04 +03:00
_log_suppress = suppress ;
2006-04-13 21:32:24 +04:00
return old_suppress ;
2002-03-16 01:54:04 +03:00
}
2003-07-05 02:34:56 +04:00
void release_log_memory ( void )
2002-03-16 01:54:04 +03:00
{
2004-03-08 21:13:22 +03:00
if ( ! _log_direct )
return ;
2005-10-17 03:03:59 +04:00
dm_free ( ( char * ) _log_dev_alias . str ) ;
2003-07-05 02:34:56 +04:00
_log_dev_alias . str = " activate_log file " ;
}
void fin_log ( void )
{
if ( _log_direct ) {
2012-03-02 01:12:37 +04:00
( void ) dev_close ( & _log_dev ) ;
2003-07-05 02:34:56 +04:00
_log_direct = 0 ;
}
if ( _log_to_file ) {
2007-07-24 21:48:08 +04:00
if ( dm_fclose ( _log_file ) ) {
if ( errno )
fprintf ( stderr , " failed to write log file: %s \n " ,
strerror ( errno ) ) ;
else
fprintf ( stderr , " failed to write log file \n " ) ;
}
2003-07-05 02:34:56 +04:00
_log_to_file = 0 ;
}
2001-08-21 16:56:08 +04:00
}
2011-04-08 18:13:08 +04:00
void fin_syslog ( void )
2002-03-16 01:54:04 +03:00
{
2002-01-19 00:26:37 +03:00
if ( _syslog )
closelog ( ) ;
2001-08-21 16:56:08 +04:00
_syslog = 0 ;
}
2002-03-16 01:54:04 +03:00
void init_msg_prefix ( const char * prefix )
{
2012-02-08 15:05:04 +04:00
strncpy ( _msg_prefix , prefix , sizeof ( _msg_prefix ) - 1 ) ;
2002-01-22 18:33:40 +03:00
_msg_prefix [ sizeof ( _msg_prefix ) - 1 ] = ' \0 ' ;
}
2002-03-16 01:54:04 +03:00
void init_indent ( int indent )
{
2002-01-22 18:33:40 +03:00
_indent = indent ;
}
2009-11-30 20:17:11 +03:00
void init_abort_on_internal_errors ( int fatal )
{
_abort_on_internal_errors = fatal ;
}
2009-07-16 03:57:54 +04:00
void reset_lvm_errno ( int store_errmsg )
{
_lvm_errno = 0 ;
if ( _lvm_errmsg ) {
dm_free ( _lvm_errmsg ) ;
_lvm_errmsg = NULL ;
2011-03-30 16:53:04 +04:00
_lvm_errmsg_size = _lvm_errmsg_len = 0 ;
2009-07-16 03:57:54 +04:00
}
_store_errmsg = store_errmsg ;
}
2009-07-16 04:36:59 +04:00
int stored_errno ( void )
2009-07-16 03:57:54 +04:00
{
return _lvm_errno ;
}
2009-07-16 04:36:59 +04:00
const char * stored_errmsg ( void )
2009-07-16 03:57:54 +04:00
{
return _lvm_errmsg ? : " " ;
}
2010-05-06 02:37:52 +04:00
static struct dm_hash_table * _duplicated = NULL ;
void reset_log_duplicated ( void ) {
2012-03-28 15:11:25 +04:00
if ( _duplicated ) {
2010-05-06 02:37:52 +04:00
dm_hash_destroy ( _duplicated ) ;
2012-03-28 15:11:25 +04:00
_duplicated = NULL ;
}
2010-05-06 02:37:52 +04:00
}
2009-07-16 03:57:54 +04:00
void print_log ( int level , const char * file , int line , int dm_errno ,
const char * format , . . . )
2002-03-16 01:54:04 +03:00
{
2001-08-21 16:56:08 +04:00
va_list ap ;
2011-10-22 20:52:00 +04:00
char buf [ 1024 ] , locn [ 4096 ] ;
2003-07-05 02:34:56 +04:00
int bufused , n ;
2004-03-26 17:47:14 +03:00
const char * message ;
const char * trformat ; /* Translated format string */
2009-07-16 03:57:54 +04:00
char * newbuf ;
2007-06-28 21:33:44 +04:00
int use_stderr = level & _LOG_STDERR ;
2010-05-06 02:37:52 +04:00
int log_once = level & _LOG_ONCE ;
2010-01-11 23:41:39 +03:00
int fatal_internal_error = 0 ;
2011-03-30 16:53:04 +04:00
size_t msglen ;
2007-06-28 21:33:44 +04:00
2010-05-06 02:37:52 +04:00
level & = ~ ( _LOG_STDERR | _LOG_ONCE ) ;
2004-02-14 01:56:45 +03:00
2009-12-01 16:54:27 +03:00
if ( _abort_on_internal_errors & &
2009-12-16 22:22:11 +03:00
! strncmp ( format , INTERNAL_ERROR ,
2010-01-11 23:41:39 +03:00
strlen ( INTERNAL_ERROR ) ) ) {
fatal_internal_error = 1 ;
2010-01-11 23:30:32 +03:00
/* Internal errors triggering abort cannot be suppressed. */
2010-01-11 23:41:39 +03:00
_log_suppress = 0 ;
level = _LOG_FATAL ;
}
if ( _log_suppress = = 2 )
2006-04-13 21:32:24 +04:00
return ;
2008-06-06 23:28:35 +04:00
if ( level < = _LOG_ERR )
2008-10-30 20:27:28 +03:00
init_error_message_produced ( 1 ) ;
2008-06-06 23:28:35 +04:00
2004-02-14 01:56:45 +03:00
trformat = _ ( format ) ;
2001-08-21 16:56:08 +04:00
2009-07-16 03:57:54 +04:00
if ( dm_errno & & ! _lvm_errno )
_lvm_errno = dm_errno ;
2010-05-06 02:37:52 +04:00
if ( _lvm2_log_fn | |
( _store_errmsg & & ( level < = _LOG_ERR ) ) | |
log_once ) {
2004-03-26 17:47:14 +03:00
va_start ( ap , format ) ;
2011-10-22 20:52:00 +04:00
n = vsnprintf ( locn , sizeof ( locn ) - 1 , trformat , ap ) ;
2004-03-26 17:47:14 +03:00
va_end ( ap ) ;
if ( n < 0 ) {
fprintf ( stderr , _ ( " vsnprintf failed: skipping external "
" logging function " ) ) ;
goto log_it ;
}
2011-10-22 20:52:00 +04:00
locn [ sizeof ( locn ) - 1 ] = ' \0 ' ;
2012-03-28 15:11:25 +04:00
message = locn ;
2009-07-16 03:57:54 +04:00
}
2004-03-26 17:47:14 +03:00
2011-04-29 04:21:13 +04:00
/* FIXME Avoid pointless use of message buffer when it'll never be read! */
2011-03-30 16:53:04 +04:00
if ( _store_errmsg & & ( level < = _LOG_ERR ) & &
_lvm_errmsg_len < MAX_ERRMSG_LEN ) {
msglen = strlen ( message ) ;
if ( ( _lvm_errmsg_len + msglen + 1 ) > = _lvm_errmsg_size ) {
_lvm_errmsg_size = 2 * ( _lvm_errmsg_len + msglen + 1 ) ;
if ( ( newbuf = dm_realloc ( _lvm_errmsg ,
_lvm_errmsg_size ) ) )
_lvm_errmsg = newbuf ;
else
_lvm_errmsg_size = _lvm_errmsg_len ;
}
if ( _lvm_errmsg & &
( _lvm_errmsg_len + msglen + 2 ) < _lvm_errmsg_size ) {
/* prepend '\n' and copy with '\0' but do not count in */
if ( _lvm_errmsg_len )
_lvm_errmsg [ _lvm_errmsg_len + + ] = ' \n ' ;
memcpy ( _lvm_errmsg + _lvm_errmsg_len , message , msglen + 1 ) ;
_lvm_errmsg_len + = msglen ;
2009-07-16 03:57:54 +04:00
}
}
2010-05-06 02:37:52 +04:00
if ( log_once ) {
if ( ! _duplicated )
_duplicated = dm_hash_create ( 128 ) ;
if ( _duplicated ) {
if ( dm_hash_lookup ( _duplicated , message ) )
level = _LOG_NOTICE ;
2012-02-27 15:31:30 +04:00
( void ) dm_hash_insert ( _duplicated , message , ( void * ) 1 ) ;
2010-05-06 02:37:52 +04:00
}
}
2009-07-16 03:57:54 +04:00
if ( _lvm2_log_fn ) {
_lvm2_log_fn ( level , file , line , 0 , message ) ;
2010-03-23 21:18:49 +03:00
if ( fatal_internal_error )
abort ( ) ;
2004-03-26 17:47:14 +03:00
return ;
}
log_it :
2002-03-16 01:54:04 +03:00
if ( ! _log_suppress ) {
2008-10-30 20:27:28 +03:00
if ( verbose_level ( ) > _LOG_DEBUG )
2011-08-11 23:21:42 +04:00
( void ) dm_snprintf ( locn , sizeof ( locn ) , " #%s:%d " ,
file , line ) ;
2004-12-10 19:01:35 +03:00
else
locn [ 0 ] = ' \0 ' ;
2002-03-16 01:54:04 +03:00
va_start ( ap , format ) ;
switch ( level ) {
case _LOG_DEBUG :
2004-12-10 19:01:35 +03:00
if ( ! strcmp ( " <backtrace> " , format ) & &
2008-10-30 20:27:28 +03:00
verbose_level ( ) < = _LOG_DEBUG )
2002-03-16 01:54:04 +03:00
break ;
2010-01-11 23:41:39 +03:00
if ( verbose_level ( ) > = _LOG_DEBUG ) {
2008-10-30 20:27:28 +03:00
fprintf ( stderr , " %s%s%s " , locn , log_command_name ( ) ,
2004-12-10 19:01:35 +03:00
_msg_prefix ) ;
2002-03-16 01:54:04 +03:00
if ( _indent )
2004-12-10 19:01:35 +03:00
fprintf ( stderr , " " ) ;
vfprintf ( stderr , trformat , ap ) ;
fputc ( ' \n ' , stderr ) ;
2002-03-16 01:54:04 +03:00
}
2002-02-21 00:26:40 +03:00
break ;
2001-08-21 16:56:08 +04:00
2002-03-16 01:54:04 +03:00
case _LOG_INFO :
2010-01-11 23:41:39 +03:00
if ( verbose_level ( ) > = _LOG_INFO ) {
2008-10-30 20:27:28 +03:00
fprintf ( stderr , " %s%s%s " , locn , log_command_name ( ) ,
2004-12-10 19:01:35 +03:00
_msg_prefix ) ;
2002-03-16 01:54:04 +03:00
if ( _indent )
2004-12-10 19:01:35 +03:00
fprintf ( stderr , " " ) ;
vfprintf ( stderr , trformat , ap ) ;
fputc ( ' \n ' , stderr ) ;
2002-03-16 01:54:04 +03:00
}
break ;
case _LOG_NOTICE :
2010-01-11 23:41:39 +03:00
if ( verbose_level ( ) > = _LOG_NOTICE ) {
2008-10-30 20:27:28 +03:00
fprintf ( stderr , " %s%s%s " , locn , log_command_name ( ) ,
2004-12-10 19:01:35 +03:00
_msg_prefix ) ;
2002-03-16 01:54:04 +03:00
if ( _indent )
2004-12-10 19:01:35 +03:00
fprintf ( stderr , " " ) ;
vfprintf ( stderr , trformat , ap ) ;
fputc ( ' \n ' , stderr ) ;
2002-03-16 01:54:04 +03:00
}
break ;
case _LOG_WARN :
2010-01-11 23:41:39 +03:00
if ( verbose_level ( ) > = _LOG_WARN ) {
2008-04-07 17:53:26 +04:00
fprintf ( use_stderr ? stderr : stdout , " %s%s " ,
2008-10-30 20:27:28 +03:00
log_command_name ( ) , _msg_prefix ) ;
2007-06-28 21:33:44 +04:00
vfprintf ( use_stderr ? stderr : stdout , trformat , ap ) ;
fputc ( ' \n ' , use_stderr ? stderr : stdout ) ;
2004-03-26 14:45:01 +03:00
}
2002-03-16 01:54:04 +03:00
break ;
case _LOG_ERR :
2010-01-11 23:41:39 +03:00
if ( verbose_level ( ) > = _LOG_ERR ) {
2008-10-30 20:27:28 +03:00
fprintf ( stderr , " %s%s%s " , locn , log_command_name ( ) ,
2004-12-10 19:01:35 +03:00
_msg_prefix ) ;
2004-03-26 14:45:01 +03:00
vfprintf ( stderr , trformat , ap ) ;
fputc ( ' \n ' , stderr ) ;
}
2002-03-16 01:54:04 +03:00
break ;
case _LOG_FATAL :
default :
2010-01-11 23:41:39 +03:00
if ( verbose_level ( ) > = _LOG_FATAL ) {
2008-10-30 20:27:28 +03:00
fprintf ( stderr , " %s%s%s " , locn , log_command_name ( ) ,
2004-12-10 19:01:35 +03:00
_msg_prefix ) ;
2004-03-26 14:45:01 +03:00
vfprintf ( stderr , trformat , ap ) ;
fputc ( ' \n ' , stderr ) ;
}
2002-03-16 01:54:04 +03:00
break ;
2001-08-21 16:56:08 +04:00
}
2002-03-16 01:54:04 +03:00
va_end ( ap ) ;
2001-08-21 16:56:08 +04:00
}
2010-01-11 23:41:39 +03:00
if ( fatal_internal_error )
2009-11-30 20:17:11 +03:00
abort ( ) ;
2008-10-30 20:27:28 +03:00
if ( level > debug_level ( ) )
2001-08-21 16:56:08 +04:00
return ;
2011-02-18 17:16:11 +03:00
if ( _log_to_file & & ( _log_while_suspended | | ! critical_section ( ) ) ) {
2008-10-30 20:27:28 +03:00
fprintf ( _log_file , " %s:%d %s%s " , file , line , log_command_name ( ) ,
2003-07-05 02:34:56 +04:00
_msg_prefix ) ;
2001-08-21 16:56:08 +04:00
va_start ( ap , format ) ;
2004-02-14 01:56:45 +03:00
vfprintf ( _log_file , trformat , ap ) ;
2001-08-21 16:56:08 +04:00
va_end ( ap ) ;
2003-07-05 02:34:56 +04:00
fprintf ( _log_file , " \n " ) ;
fflush ( _log_file ) ;
2001-08-21 16:56:08 +04:00
}
2011-02-18 17:16:11 +03:00
if ( _syslog & & ( _log_while_suspended | | ! critical_section ( ) ) ) {
2002-03-16 01:54:04 +03:00
va_start ( ap , format ) ;
2004-02-14 01:56:45 +03:00
vsyslog ( level , trformat , ap ) ;
2001-08-21 16:56:08 +04:00
va_end ( ap ) ;
}
2003-07-05 02:34:56 +04:00
/* FIXME This code is unfinished - pre-extend & condense. */
2011-02-18 17:16:11 +03:00
if ( ! _already_logging & & _log_direct & & critical_section ( ) ) {
2003-07-05 02:34:56 +04:00
_already_logging = 1 ;
memset ( & buf , ' ' , sizeof ( buf ) ) ;
bufused = 0 ;
2010-10-26 12:53:25 +04:00
if ( ( n = dm_snprintf ( buf , sizeof ( buf ) - 1 ,
2008-10-30 20:27:28 +03:00
" %s:%d %s%s " , file , line , log_command_name ( ) ,
2003-07-05 02:34:56 +04:00
_msg_prefix ) ) = = - 1 )
goto done ;
bufused + = n ;
va_start ( ap , format ) ;
n = vsnprintf ( buf + bufused - 1 , sizeof ( buf ) - bufused - 1 ,
2004-02-14 01:56:45 +03:00
trformat , ap ) ;
2003-07-05 02:34:56 +04:00
va_end ( ap ) ;
bufused + = n ;
buf [ bufused - 1 ] = ' \n ' ;
2012-02-08 15:31:29 +04:00
done :
2003-07-05 02:34:56 +04:00
buf [ bufused ] = ' \n ' ;
buf [ sizeof ( buf ) - 1 ] = ' \n ' ;
/* FIXME real size bufused */
dev_append ( & _log_dev , sizeof ( buf ) , buf ) ;
_already_logging = 0 ;
}
2001-08-21 16:56:08 +04:00
}