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 ,
2016-01-21 13:49:46 +03:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2001-08-21 16:56:08 +04:00
*/
2018-05-14 12:30:20 +03:00
# include "lib/misc/lib.h"
# include "lib/device/device.h"
# include "lib/mm/memlock.h"
# include "lib/config/defaults.h"
# include "lib/report/report.h"
# include "lib/misc/lvm-file.h"
2002-11-18 17:01:16 +03:00
2015-04-20 11:04:18 +03:00
# include <stdio.h>
2001-08-21 16:56:08 +04:00
# include <stdarg.h>
# include <syslog.h>
2015-04-20 20:10:29 +03:00
# include <ctype.h>
2019-02-22 21:01:20 +03:00
# include <time.h>
2021-10-14 21:50:01 +03:00
# ifdef SYSTEMD_JOURNAL_SUPPORT
2021-03-24 22:19:54 +03:00
# include <systemd/sd-journal.h>
2021-10-14 21:50:01 +03:00
# endif
2001-08-21 16:56:08 +04:00
2003-07-05 02:34:56 +04:00
static FILE * _log_file ;
2015-04-20 11:04:18 +03:00
static char _log_file_path [ PATH_MAX ] ;
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 ;
2016-07-11 13:43:28 +03:00
static uint64_t _log_file_max_lines = 0 ;
static uint64_t _log_file_lines = 0 ;
2003-07-05 02:34:56 +04:00
static int _log_while_suspended = 0 ;
2019-02-22 21:01:20 +03:00
static int _indent = 0 ;
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 ] = " " ;
2015-07-20 17:48:59 +03:00
static int _abort_on_internal_errors_config = 0 ;
2019-02-26 23:31:44 +03:00
static uint32_t _debug_file_fields ;
static uint32_t _debug_output_fields ;
2021-03-24 22:19:54 +03:00
static uint32_t _log_journal = 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
2016-05-03 12:46:52 +03:00
static log_report_t _log_report = {
. report = NULL ,
. context = LOG_REPORT_CONTEXT_NULL ,
. object_type = LOG_REPORT_OBJECT_TYPE_NULL ,
. object_id = NULL ,
. object_name = NULL ,
. object_group = NULL
} ;
2016-07-08 17:47:51 +03:00
# define LOG_STREAM_BUFFER_SIZE 4096
struct log_stream_item {
FILE * stream ;
char * buffer ;
} ;
2016-11-02 16:26:41 +03:00
static struct log_stream {
2016-07-08 17:47:51 +03:00
struct log_stream_item out ;
struct log_stream_item err ;
struct log_stream_item report ;
} _log_stream = { { NULL , NULL } ,
{ NULL , NULL } ,
{ NULL , NULL } } ;
# define out_stream (_log_stream.out.stream ? : stdout)
# define err_stream (_log_stream.err.stream ? : stderr)
# define report_stream (_log_stream.report.stream ? : stdout)
static int _set_custom_log_stream ( struct log_stream_item * stream_item , int custom_fd )
{
FILE * final_stream = NULL ;
int flags ;
int r = 1 ;
if ( custom_fd < 0 )
goto out ;
if ( is_valid_fd ( custom_fd ) ) {
if ( ( flags = fcntl ( custom_fd , F_GETFL ) ) > 0 ) {
if ( ( flags & O_ACCMODE ) = = O_RDONLY ) {
log_error ( " File descriptor %d already open in read-only "
" mode, expected write-only or read-write mode. " ,
( int ) custom_fd ) ;
r = 0 ;
goto out ;
}
}
if ( custom_fd = = STDIN_FILENO ) {
log_error ( " Can't set standard input for log output. " ) ;
r = 0 ;
goto out ;
}
if ( custom_fd = = STDOUT_FILENO ) {
final_stream = stdout ;
goto out ;
}
if ( custom_fd = = STDERR_FILENO ) {
final_stream = stderr ;
goto out ;
}
}
if ( ! ( final_stream = fdopen ( custom_fd , " w " ) ) ) {
log_error ( " Failed to open stream for file descriptor %d. " ,
( int ) custom_fd ) ;
r = 0 ;
goto out ;
}
2018-06-08 15:40:53 +03:00
if ( ! ( stream_item - > buffer = malloc ( LOG_STREAM_BUFFER_SIZE ) ) ) {
2016-07-08 17:47:51 +03:00
log_error ( " Failed to allocate buffer for stream on file "
" descriptor %d. " , ( int ) custom_fd ) ;
} else {
if ( setvbuf ( final_stream , stream_item - > buffer , _IOLBF , LOG_STREAM_BUFFER_SIZE ) ) {
log_sys_error ( " setvbuf " , " " ) ;
2018-06-08 15:40:53 +03:00
free ( stream_item - > buffer ) ;
2016-07-08 17:47:51 +03:00
stream_item - > buffer = NULL ;
}
}
out :
stream_item - > stream = final_stream ;
return r ;
}
int init_custom_log_streams ( struct custom_fds * custom_fds )
{
return _set_custom_log_stream ( & _log_stream . out , custom_fds - > out ) & &
_set_custom_log_stream ( & _log_stream . err , custom_fds - > err ) & &
_set_custom_log_stream ( & _log_stream . report , custom_fds - > report ) ;
}
static void _check_and_replace_standard_log_streams ( FILE * old_stream , FILE * new_stream )
{
if ( _log_stream . out . stream = = old_stream )
_log_stream . out . stream = new_stream ;
if ( _log_stream . err . stream = = old_stream )
_log_stream . err . stream = new_stream ;
if ( _log_stream . report . stream = = old_stream )
_log_stream . report . stream = new_stream ;
}
/*
* Close and reopen standard stream on file descriptor fd .
*/
int reopen_standard_stream ( FILE * * stream , const char * mode )
{
int fd , fd_copy , new_fd ;
const char * name ;
FILE * old_stream = * stream ;
FILE * new_stream ;
if ( old_stream = = stdin ) {
fd = STDIN_FILENO ;
name = " stdin " ;
} else if ( old_stream = = stdout ) {
fd = STDOUT_FILENO ;
name = " stdout " ;
} else if ( old_stream = = stderr ) {
fd = STDERR_FILENO ;
name = " stderr " ;
} else {
log_error ( INTERNAL_ERROR " reopen_standard_stream called on non-standard stream " ) ;
return 0 ;
}
if ( ( fd_copy = dup ( fd ) ) < 0 ) {
log_sys_error ( " dup " , name ) ;
return 0 ;
}
if ( fclose ( old_stream ) )
log_sys_error ( " fclose " , name ) ;
if ( ( new_fd = dup2 ( fd_copy , fd ) ) < 0 )
log_sys_error ( " dup2 " , name ) ;
else if ( new_fd ! = fd )
log_error ( " dup2(%d, %d) returned %d " , fd_copy , fd , new_fd ) ;
if ( close ( fd_copy ) < 0 )
log_sys_error ( " close " , name ) ;
if ( ! ( new_stream = fdopen ( fd , mode ) ) ) {
log_sys_error ( " fdopen " , name ) ;
return 0 ;
}
_check_and_replace_standard_log_streams ( old_stream , new_stream ) ;
* stream = new_stream ;
return 1 ;
}
2004-03-26 17:47:14 +03:00
void init_log_fn ( lvm2_log_fn_t log_fn )
{
2015-10-09 22:37:12 +03:00
_lvm2_log_fn = log_fn ;
2004-03-26 17:47:14 +03:00
}
2023-07-10 22:44:24 +03:00
/* Read /proc/self/stat to extract pid and starttime */
static int _get_pid_starttime ( int * pid , unsigned long long * starttime )
{
static const char statfile [ ] = " /proc/self/stat " ;
char buf [ 1024 ] ;
char * p ;
int fd ;
int e ;
if ( ( fd = open ( statfile , O_RDONLY ) ) = = - 1 ) {
log_sys_debug ( " open " , statfile ) ;
return 0 ;
}
if ( ( e = read ( fd , buf , sizeof ( buf ) - 1 ) ) < = 0 )
log_sys_debug ( " read " , statfile ) ;
2023-09-25 19:28:50 +03:00
if ( close ( fd ) )
2023-07-10 22:44:24 +03:00
log_sys_debug ( " close " , statfile ) ;
if ( e < = 0 )
return 0 ;
buf [ e ] = ' \0 ' ;
if ( ( sscanf ( buf , " %d " , pid ) = = 1 ) & &
/* Jump past COMM, don't use scanf with '%s' since COMM may contain a space. */
( p = strrchr ( buf , ' ) ' ) ) & &
2023-07-13 22:19:48 +03:00
( sscanf ( + + p , " %*c %*d %*d %*d %*d " /* tty_nr */
" %*d %*u %*u %*u %*u " /* mjflt */
" %*u %*u %*u %*d %*d " /* cstim */
" %*d %*d %*d %*d " /* itrealvalue */
2023-07-13 22:52:20 +03:00
" %llu " , starttime ) = = 1 ) )
2023-07-10 22:44:24 +03:00
return 1 ;
log_debug ( " Cannot parse content of %s. " , statfile ) ;
return 0 ;
}
2015-04-20 11:04:18 +03:00
/*
* Support envvar LVM_LOG_FILE_EPOCH and allow to attach
2015-04-20 20:10:29 +03:00
* extra keyword ( consist of upto 32 alpha chars ) to
* opened log file . After this ' epoch ' word pid and starttime
* ( in kernel units , read from / proc / self / stat )
2015-04-20 11:04:18 +03:00
* is automatically attached .
* If command / daemon forks multiple times , it could create multiple
2015-04-20 20:10:29 +03:00
* log files ensuring , there are no overwrites .
2015-04-20 11:04:18 +03:00
*/
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
{
2015-04-20 11:04:18 +03:00
const char * env ;
2023-07-10 22:44:24 +03:00
int pid = 0 ;
unsigned long long starttime = 0 ;
2015-04-20 20:10:29 +03:00
int i = 0 ;
2015-04-20 11:04:18 +03:00
_log_file_path [ 0 ] = ' \0 ' ;
if ( ( env = getenv ( " LVM_LOG_FILE_EPOCH " ) ) ) {
2015-04-20 20:10:29 +03:00
while ( isalpha ( env [ i ] ) & & i < 32 ) /* Up to 32 alphas */
i + + ;
if ( env [ i ] ) {
if ( i )
log_warn ( " WARNING: Ignoring invalid LVM_LOG_FILE_EPOCH envvar \" %s \" . " , env ) ;
goto no_epoch ;
}
2023-07-10 22:44:24 +03:00
if ( ! _get_pid_starttime ( & pid , & starttime ) )
log_debug ( " Failed to obtain pid and starttime. " ) ;
if ( dm_snprintf ( _log_file_path , sizeof ( _log_file_path ) ,
" %s_%s_%d_%llu " , log_file , env , pid , starttime ) < 0 ) {
log_warn ( " WARNING: Debug log file path is too long for epoch. " ) ;
_log_file_path [ 0 ] = ' \0 ' ;
2015-04-20 11:04:18 +03:00
} else {
2023-07-10 22:44:24 +03:00
log_file = _log_file_path ;
append = 1 ; /* force */
2015-04-20 11:04:18 +03:00
}
2015-07-08 16:35:37 +03:00
2016-07-11 13:43:28 +03:00
if ( ( env = getenv ( " LVM_LOG_FILE_MAX_LINES " ) ) ) {
if ( sscanf ( env , FMTu64 , & _log_file_max_lines ) ! = 1 ) {
2016-07-11 15:45:25 +03:00
log_warn ( " WARNING: Ignoring invalid LVM_LOG_MAX_LINES envvar \" %s \" . " , env ) ;
2016-07-11 13:43:28 +03:00
_log_file_max_lines = 0 ;
}
_log_file_lines = 0 ;
}
2015-04-20 11:04:18 +03:00
}
2015-07-08 14:56:06 +03:00
2015-04-20 20:10:29 +03:00
no_epoch :
2015-04-20 11:04:18 +03:00
if ( ! ( _log_file = fopen ( log_file , append ? " a " : " w " ) ) ) {
2003-07-05 02:34:56 +04:00
log_sys_error ( " fopen " , log_file ) ;
return ;
}
_log_to_file = 1 ;
}
2015-04-20 11:04:18 +03:00
/*
* Unlink the log file depeding on command ' s return value
*
2015-04-20 20:10:29 +03:00
* When envvar LVM_EXPECTED_EXIT_STATUS is set , compare
2015-04-20 11:04:18 +03:00
* resulting status with this string .
*
* It ' s possible to specify 2 variants - having it equal to
* a single number or having it different from a single number .
*
2015-04-20 20:10:29 +03:00
* i . e . LVM_EXPECTED_EXIT_STATUS = " >1 " # delete when ret > 1.
2015-04-20 11:04:18 +03:00
*/
void unlink_log_file ( int ret )
{
const char * env ;
if ( _log_file_path [ 0 ] & &
2015-04-20 20:10:29 +03:00
( env = getenv ( " LVM_EXPECTED_EXIT_STATUS " ) ) & &
( ( env [ 0 ] = = ' > ' & & ret > atoi ( env + 1 ) ) | |
2015-04-20 11:04:18 +03:00
( atoi ( env ) = = ret ) ) ) {
if ( unlink ( _log_file_path ) )
log_sys_error ( " unlink " , _log_file_path ) ;
_log_file_path [ 0 ] = ' \0 ' ;
}
}
2003-07-05 02:34:56 +04:00
void init_log_while_suspended ( int log_while_suspended )
{
_log_while_suspended = log_while_suspended ;
2001-08-21 16:56:08 +04:00
}
2021-10-12 01:08:05 +03:00
void init_syslog ( int enable , int facility )
2002-03-16 01:54:04 +03:00
{
2021-10-12 01:08:05 +03:00
if ( ! enable ) {
_syslog = 0 ;
return ;
}
2019-01-07 17:48:39 +03:00
if ( getenv ( " LVM_SUPPRESS_SYSLOG " ) )
return ;
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 fin_log ( void )
{
if ( _log_to_file ) {
2007-07-24 21:48:08 +04:00
if ( dm_fclose ( _log_file ) ) {
if ( errno )
2016-07-08 17:47:51 +03:00
fprintf ( err_stream , " failed to write log file: %s \n " ,
2007-07-24 21:48:08 +04:00
strerror ( errno ) ) ;
else
2016-07-08 17:47:51 +03:00
fprintf ( err_stream , " failed to write log file \n " ) ;
2007-07-24 21:48:08 +04:00
}
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 )
{
2017-06-27 11:17:33 +03:00
if ( prefix )
2018-02-25 18:18:31 +03:00
/* Cut away too long prefix */
( void ) dm_strncpy ( _msg_prefix , prefix , sizeof ( _msg_prefix ) ) ;
2002-01-22 18:33:40 +03:00
}
2002-03-16 01:54:04 +03:00
void init_indent ( int indent )
{
2002-01-22 18:33:40 +03:00
_indent = indent ;
}
2015-07-20 17:48:59 +03:00
/* If present, environment setting will override this. */
2009-11-30 20:17:11 +03:00
void init_abort_on_internal_errors ( int fatal )
{
2015-07-20 17:48:59 +03:00
_abort_on_internal_errors_config = fatal ;
2009-11-30 20:17:11 +03:00
}
2009-07-16 03:57:54 +04:00
void reset_lvm_errno ( int store_errmsg )
{
_lvm_errno = 0 ;
if ( _lvm_errmsg ) {
2018-06-08 15:40:53 +03:00
free ( _lvm_errmsg ) ;
2009-07-16 03:57:54 +04:00
_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 ? : " " ;
}
2013-09-26 21:19:18 +04:00
const char * stored_errmsg_with_clear ( void )
{
const char * rc = strdup ( stored_errmsg ( ) ) ;
reset_lvm_errno ( 1 ) ;
return rc ;
}
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
}
2016-05-19 13:19:48 +03:00
static const char * _get_log_level_name ( int use_stderr , int level )
2016-05-03 12:46:52 +03:00
{
static const char * log_level_names [ ] = { " " , /* unassigned */
" " , /* unassigned */
" fatal " , /* _LOG_FATAL */
" error " , /* _LOG_ERROR */
" warn " , /* _LOG_WARN */
2016-06-27 11:12:41 +03:00
" notice " , /* _LOG_NOTICE */
2016-05-03 12:46:52 +03:00
" info " , /* _LOG_INFO */
" debug " /* _LOG_DEBUG */
} ;
2016-05-19 13:19:48 +03:00
if ( level = = _LOG_WARN & & ! use_stderr )
return " print " ;
2016-05-03 12:46:52 +03:00
return log_level_names [ level ] ;
}
const char * log_get_report_context_name ( log_report_context_t context )
{
static const char * log_context_names [ LOG_REPORT_CONTEXT_COUNT ] = { [ LOG_REPORT_CONTEXT_NULL ] = " " ,
2016-07-25 13:20:22 +03:00
[ LOG_REPORT_CONTEXT_SHELL ] = " shell " ,
2016-05-03 12:46:52 +03:00
[ LOG_REPORT_CONTEXT_PROCESSING ] = " processing " } ;
return log_context_names [ context ] ;
}
const char * log_get_report_object_type_name ( log_report_object_type_t object_type )
{
static const char * log_object_type_names [ LOG_REPORT_OBJECT_TYPE_COUNT ] = { [ LOG_REPORT_OBJECT_TYPE_NULL ] = " " ,
2022-08-22 14:59:08 +03:00
[ LOG_REPORT_OBJECT_TYPE_PRE_CMD ] = " pre-cmd " ,
2016-07-25 13:20:22 +03:00
[ LOG_REPORT_OBJECT_TYPE_CMD ] = " cmd " ,
2016-06-14 14:21:53 +03:00
[ LOG_REPORT_OBJECT_TYPE_ORPHAN ] = " orphan " ,
2016-05-03 12:46:52 +03:00
[ LOG_REPORT_OBJECT_TYPE_PV ] = " pv " ,
2016-06-20 14:46:35 +03:00
[ LOG_REPORT_OBJECT_TYPE_LABEL ] = " label " ,
2016-05-03 12:46:52 +03:00
[ LOG_REPORT_OBJECT_TYPE_VG ] = " vg " ,
[ LOG_REPORT_OBJECT_TYPE_LV ] = " lv " } ;
return log_object_type_names [ object_type ] ;
}
2019-02-26 23:31:44 +03:00
void init_debug_file_fields ( uint32_t debug_fields )
{
_debug_file_fields = debug_fields ;
}
void init_debug_output_fields ( uint32_t debug_fields )
{
_debug_output_fields = debug_fields ;
}
2021-03-24 22:19:54 +03:00
void init_log_journal ( uint32_t fields )
{
_log_journal = fields ;
}
2019-02-22 21:01:20 +03:00
static void _set_time_prefix ( char * prefix , int buflen )
{
struct timespec ts ;
struct tm time_info ;
int len ;
if ( clock_gettime ( CLOCK_REALTIME , & ts ) < 0 )
goto fail ;
if ( ! localtime_r ( & ts . tv_sec , & time_info ) )
goto fail ;
len = strftime ( prefix , buflen , " %H:%M:%S " , & time_info ) ;
if ( ! len )
goto fail ;
2023-09-06 16:28:29 +03:00
len = dm_snprintf ( prefix + len , buflen - len , " .%06d " , ( int ) ts . tv_nsec / 1000 ) ;
2019-02-22 21:01:20 +03:00
if ( len < 0 )
goto fail ;
return ;
fail :
* prefix = ' \0 ' ;
}
2016-06-23 14:39:38 +03:00
__attribute__ ( ( format ( printf , 5 , 0 ) ) )
static void _vprint_log ( int level , const char * file , int line , int dm_errno_or_class ,
const char * format , va_list orig_ap )
2002-03-16 01:54:04 +03:00
{
2001-08-21 16:56:08 +04:00
va_list ap ;
2015-12-03 17:28:01 +03:00
char buf [ 1024 ] , message [ 4096 ] ;
2019-02-22 21:01:20 +03:00
char time_prefix [ 32 ] = " " ;
2019-02-26 23:31:44 +03:00
const char * command_prefix = NULL ;
2019-02-28 19:30:54 +03:00
int n ;
2004-03-26 17:47:14 +03:00
const char * trformat ; /* Translated format string */
2009-07-16 03:57:54 +04:00
char * newbuf ;
2016-11-02 16:39:13 +03:00
int use_stderr = log_stderr ( level ) ;
int log_once = log_once ( level ) ;
int log_bypass_report = log_bypass_report ( level ) ;
2010-01-11 23:41:39 +03:00
int fatal_internal_error = 0 ;
2011-03-30 16:53:04 +04:00
size_t msglen ;
2012-03-26 15:50:44 +04:00
const char * indent_spaces = " " ;
FILE * stream ;
2015-07-20 17:48:59 +03:00
static int _abort_on_internal_errors_env_present = - 1 ;
static int _abort_on_internal_errors_env = 0 ;
char * env_str ;
2016-05-03 12:46:52 +03:00
struct dm_report * orig_report ;
int logged_via_report = 0 ;
2007-06-28 21:33:44 +04:00
2016-11-02 16:39:13 +03:00
level = log_level ( level ) ;
2004-02-14 01:56:45 +03:00
2015-07-20 17:48:59 +03:00
if ( _abort_on_internal_errors_env_present < 0 ) {
if ( ( env_str = getenv ( " DM_ABORT_ON_INTERNAL_ERRORS " ) ) ) {
_abort_on_internal_errors_env_present = 1 ;
/* Set when env DM_ABORT_ON_INTERNAL_ERRORS is not "0" */
_abort_on_internal_errors_env = strcmp ( env_str , " 0 " ) ;
} else
_abort_on_internal_errors_env_present = 0 ;
}
/* Use value from environment if present, otherwise use value from config. */
if ( ( ( _abort_on_internal_errors_env_present & & _abort_on_internal_errors_env ) | |
( ! _abort_on_internal_errors_env_present & & _abort_on_internal_errors_config ) ) & &
2013-07-25 16:18:18 +04:00
! strncmp ( format , INTERNAL_ERROR , sizeof ( INTERNAL_ERROR ) - 1 ) ) {
2010-01-11 23:41:39 +03:00
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 ;
}
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
2013-01-08 02:25:19 +04:00
if ( level < _LOG_DEBUG & & dm_errno_or_class & & ! _lvm_errno )
_lvm_errno = dm_errno_or_class ;
2009-07-16 03:57:54 +04:00
2010-05-06 02:37:52 +04:00
if ( _lvm2_log_fn | |
( _store_errmsg & & ( level < = _LOG_ERR ) ) | |
2016-05-19 13:19:48 +03:00
( _log_report . report & & ! log_bypass_report & & ( use_stderr | | ( level < = _LOG_WARN ) ) ) | |
2010-05-06 02:37:52 +04:00
log_once ) {
2016-06-23 14:39:38 +03:00
va_copy ( ap , orig_ap ) ;
2015-12-03 17:28:01 +03:00
n = vsnprintf ( message , sizeof ( message ) , trformat , ap ) ;
2004-03-26 17:47:14 +03:00
va_end ( ap ) ;
2015-12-03 17:28:01 +03:00
/* When newer glibc returns >= sizeof(locn), we will just log what
* has fit into buffer , it ' s ' \0 ' terminated string */
2004-03-26 17:47:14 +03:00
if ( n < 0 ) {
2016-07-08 17:47:51 +03:00
fprintf ( err_stream , _ ( " vsnprintf failed: skipping external "
" logging function " ) ) ;
2004-03-26 17:47:14 +03:00
goto log_it ;
}
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 ) ;
2018-06-08 15:40:53 +03:00
if ( ( newbuf = realloc ( _lvm_errmsg ,
2011-03-30 16:53:04 +04:00
_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 )
2021-03-07 17:33:50 +03:00
_duplicated = dm_hash_create ( 117 ) ;
2010-05-06 02:37:52 +04:00
if ( _duplicated ) {
if ( dm_hash_lookup ( _duplicated , message ) )
level = _LOG_NOTICE ;
2014-04-07 19:51:42 +04:00
else
( void ) dm_hash_insert ( _duplicated , message , ( void * ) 1 ) ;
2010-05-06 02:37:52 +04:00
}
}
2016-05-19 13:19:48 +03:00
if ( _log_report . report & & ! log_bypass_report & & ( use_stderr | | ( level < = _LOG_WARN ) ) ) {
2016-05-03 12:46:52 +03:00
orig_report = _log_report . report ;
_log_report . report = NULL ;
2016-05-19 13:19:48 +03:00
if ( ! report_cmdlog ( orig_report , _get_log_level_name ( use_stderr , level ) ,
2016-05-03 12:46:52 +03:00
log_get_report_context_name ( _log_report . context ) ,
log_get_report_object_type_name ( _log_report . object_type ) ,
_log_report . object_name , _log_report . object_id ,
_log_report . object_group , _log_report . object_group_id ,
message , _lvm_errno , 0 ) )
2016-07-08 17:47:51 +03:00
fprintf ( err_stream , _ ( " failed to report cmdstatus " ) ) ;
2016-05-03 12:46:52 +03:00
else
logged_via_report = 1 ;
_log_report . report = orig_report ;
}
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 :
2021-03-24 22:19:54 +03:00
2021-10-14 21:50:01 +03:00
# ifdef SYSTEMD_JOURNAL_SUPPORT
2021-03-24 22:19:54 +03:00
if ( _log_journal ) {
int to_journal = 0 ;
/* By default the visible command output is _LOG_WARN or less. */
if ( _log_journal & LOG_JOURNAL_DEBUG )
to_journal = 1 ;
if ( ( _log_journal & LOG_JOURNAL_OUTPUT ) & & ( log_level ( level ) < = _LOG_WARN ) )
to_journal = 1 ;
if ( to_journal ) {
int prio ;
switch ( log_level ( level ) ) {
case _LOG_ERR : prio = LOG_ERR ; break ;
case _LOG_WARN : prio = LOG_WARNING ; break ;
case _LOG_INFO : prio = LOG_INFO ; break ;
case _LOG_NOTICE : prio = LOG_NOTICE ; break ;
case _LOG_DEBUG : prio = LOG_DEBUG ; break ;
default : prio = LOG_INFO ;
}
va_copy ( ap , orig_ap ) ;
sd_journal_printv ( prio , trformat , ap ) ;
va_end ( ap ) ;
}
}
2021-10-14 21:50:01 +03:00
# endif
2021-03-24 22:19:54 +03:00
2016-05-03 12:46:52 +03:00
if ( ! logged_via_report & & ( ( verbose_level ( ) > = level ) & & ! _log_suppress ) ) {
2012-03-26 15:50:44 +04:00
if ( verbose_level ( ) > _LOG_DEBUG ) {
2019-02-22 21:01:20 +03:00
memset ( buf , 0 , sizeof ( buf ) ) ;
2019-02-26 23:31:44 +03:00
if ( ! _debug_output_fields | | ( _debug_output_fields & LOG_DEBUG_FIELD_TIME ) ) {
if ( ! time_prefix [ 0 ] )
_set_time_prefix ( time_prefix , sizeof ( time_prefix ) ) ;
else
time_prefix [ 0 ] = ' \0 ' ;
}
2019-02-22 21:01:20 +03:00
2019-02-26 23:31:44 +03:00
if ( ! _debug_output_fields | | ( _debug_output_fields & LOG_DEBUG_FIELD_COMMAND ) )
command_prefix = log_command_file ( ) ;
else
command_prefix = NULL ;
2019-02-22 21:01:20 +03:00
2019-02-26 23:31:44 +03:00
if ( ! _debug_output_fields | | ( _debug_output_fields & LOG_DEBUG_FIELD_FILELINE ) )
( void ) dm_snprintf ( buf , sizeof ( buf ) , " %s%s %s:%d " ,
time_prefix , command_prefix ? : " " , file , line ) ;
else
( void ) dm_snprintf ( buf , sizeof ( buf ) , " %s%s " ,
time_prefix , command_prefix ? : " " ) ;
2019-02-22 21:01:20 +03:00
} else {
memset ( buf , 0 , sizeof ( buf ) ) ;
/* without -vvvv, command[pid] is controlled by config settings */
( void ) dm_snprintf ( buf , sizeof ( buf ) , " %s " , log_command_info ( ) ) ;
}
2012-03-26 15:50:44 +04:00
if ( _indent )
switch ( level ) {
case _LOG_NOTICE : indent_spaces = " " ; break ;
case _LOG_INFO : indent_spaces = " " ; break ;
case _LOG_DEBUG : indent_spaces = " " ; break ;
default : /* nothing to do */ ;
}
2004-12-10 19:01:35 +03:00
2016-06-23 14:39:38 +03:00
va_copy ( ap , orig_ap ) ;
2002-03-16 01:54:04 +03:00
switch ( level ) {
case _LOG_DEBUG :
2013-01-08 02:25:19 +04:00
if ( verbose_level ( ) < _LOG_DEBUG )
break ;
if ( ! debug_class_is_logged ( dm_errno_or_class ) )
break ;
2015-04-13 12:39:23 +03:00
if ( ( verbose_level ( ) = = level ) & &
( strcmp ( " <backtrace> " , format ) = = 0 ) )
break ;
2012-03-26 15:50:44 +04:00
/* fall through */
2002-03-16 01:54:04 +03:00
default :
2016-07-08 17:47:51 +03:00
/* Typically only log_warn goes to out_stream */
stream = ( use_stderr | | ( level ! = _LOG_WARN ) ) ? err_stream : out_stream ;
if ( stream = = err_stream )
fflush ( out_stream ) ;
2019-02-22 21:01:20 +03:00
fprintf ( stream , " %s%s%s " , buf , _msg_prefix , indent_spaces ) ;
2012-03-26 15:50:44 +04:00
vfprintf ( stream , trformat , ap ) ;
fputc ( ' \n ' , stream ) ;
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
}
2013-03-28 16:33:20 +04:00
if ( ( level > debug_level ( ) ) | |
( level > = _LOG_DEBUG & & ! debug_class_is_logged ( dm_errno_or_class ) ) ) {
if ( fatal_internal_error )
abort ( ) ;
2013-01-08 02:25:19 +04:00
return ;
2013-03-28 16:33:20 +04:00
}
2013-01-08 02:25:19 +04:00
2011-02-18 17:16:11 +03:00
if ( _log_to_file & & ( _log_while_suspended | | ! critical_section ( ) ) ) {
2019-02-22 21:01:20 +03:00
2019-02-26 23:31:44 +03:00
if ( ! _debug_file_fields | | ( _debug_file_fields & LOG_DEBUG_FIELD_TIME ) ) {
if ( ! time_prefix [ 0 ] )
_set_time_prefix ( time_prefix , sizeof ( time_prefix ) ) ;
else
time_prefix [ 0 ] = ' \0 ' ;
}
if ( ! _debug_file_fields | | ( _debug_file_fields & LOG_DEBUG_FIELD_COMMAND ) )
command_prefix = log_command_file ( ) ;
else
command_prefix = NULL ;
if ( ! _debug_file_fields | | ( _debug_file_fields & LOG_DEBUG_FIELD_FILELINE ) )
fprintf ( _log_file , " %s%s %s:%d%s " , time_prefix , command_prefix ? : " " , file , line , _msg_prefix ) ;
else
fprintf ( _log_file , " %s%s %s " , time_prefix , command_prefix ? : " " , _msg_prefix ) ;
2001-08-21 16:56:08 +04:00
2016-06-23 14:39:38 +03:00
va_copy ( ap , orig_ap ) ;
2004-02-14 01:56:45 +03:00
vfprintf ( _log_file , trformat , ap ) ;
2001-08-21 16:56:08 +04:00
va_end ( ap ) ;
2017-10-26 14:55:36 +03:00
if ( _log_file_max_lines & & + + _log_file_lines > = _log_file_max_lines ) {
2019-02-22 21:01:20 +03:00
fprintf ( _log_file , " \n %s:%d %sAborting. Command has reached limit "
2017-10-26 14:55:36 +03:00
" for logged lines (LVM_LOG_FILE_MAX_LINES= " FMTu64 " ). " ,
file , line , _msg_prefix ,
_log_file_max_lines ) ;
fatal_internal_error = 1 ;
}
2015-04-13 12:39:23 +03:00
fputc ( ' \n ' , _log_file ) ;
2003-07-05 02:34:56 +04:00
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 ( ) ) ) {
2016-06-23 14:39:38 +03:00
va_copy ( ap , orig_ap ) ;
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
2012-12-14 16:57:01 +04:00
if ( fatal_internal_error )
abort ( ) ;
2001-08-21 16:56:08 +04:00
}
2016-05-03 12:46:52 +03:00
2016-06-23 14:39:38 +03:00
void print_log ( int level , const char * file , int line , int dm_errno_or_class ,
const char * format , . . . )
{
va_list ap ;
va_start ( ap , format ) ;
_vprint_log ( level , file , line , dm_errno_or_class , format , ap ) ;
va_end ( ap ) ;
}
2016-06-23 14:55:39 +03:00
void print_log_libdm ( int level , const char * file , int line , int dm_errno_or_class ,
const char * format , . . . )
{
2016-07-08 17:47:51 +03:00
FILE * orig_out_stream = out_stream ;
2016-06-23 14:55:39 +03:00
va_list ap ;
/*
* Bypass report if printing output from libdm and if we have
* LOG_WARN level and it ' s not going to stderr ( so we ' re
* printing common message that is not an error / warning ) .
*/
2016-11-02 16:39:13 +03:00
if ( ! log_stderr ( level ) & &
( log_level ( level ) = = _LOG_WARN ) )
2016-06-23 14:55:39 +03:00
level | = _LOG_BYPASS_REPORT ;
2016-07-08 17:47:51 +03:00
_log_stream . out . stream = report_stream ;
2016-06-23 14:55:39 +03:00
va_start ( ap , format ) ;
_vprint_log ( level , file , line , dm_errno_or_class , format , ap ) ;
va_end ( ap ) ;
2016-07-08 17:47:51 +03:00
_log_stream . out . stream = orig_out_stream ;
2016-06-23 14:55:39 +03:00
}
2016-05-03 12:46:52 +03:00
log_report_t log_get_report_state ( void )
{
return _log_report ;
}
void log_restore_report_state ( log_report_t log_report )
{
_log_report = log_report ;
}
void log_set_report ( struct dm_report * report )
{
_log_report . report = report ;
}
void log_set_report_context ( log_report_context_t context )
{
_log_report . context = context ;
}
void log_set_report_object_type ( log_report_object_type_t object_type )
{
_log_report . object_type = object_type ;
}
void log_set_report_object_group_and_group_id ( const char * group , const char * id )
{
_log_report . object_group = group ;
_log_report . object_group_id = id ;
}
void log_set_report_object_name_and_id ( const char * name , const char * id )
{
_log_report . object_name = name ;
_log_report . object_id = id ;
}
2021-03-24 22:19:54 +03:00
/*
* TODO : log / journal = [ " daemon_command " ]
* daemon_command : record commands that are run by an lvm daemon .
* ( i . e . not commands run directly by a user . )
* For this we need to be able to clearly identify when a command is
* being run by dmeventd / lvmpolld / lvmdbusd .
*
* TODO : log / journal_commmand_names = [ " lvcreate " , " lvconvert " ]
* This would restrict log / journal = [ " command " ] to the listed command names .
* Also allow " !command " to exclude a command , e . g . [ " !pvs " ]
*
* TODO : log / journal_daemon_command_names = [ " lvcreate " , " lvconvert " ]
* This would restrict log / journal = [ " dameon_command " ] to the listed command names .
*
* TODO : log / journal_daemon_names = [ " dmeventd " ]
* This would restrict log / journal = [ " daemon_command " ] to commands run by
* the named daemon .
*
* TODO : log / command_to_file = < path > would write this info to the file .
*
* TODO : log / debug_to_file = < path > would write full debugging to the file .
* ( the same effect as log / file = < path > log / level = 7 )
*/
void log_command ( const char * cmd_line , const char * cmd_name , const char * cmd_id )
{
2021-10-14 21:50:01 +03:00
# ifdef SYSTEMD_JOURNAL_SUPPORT
2021-03-24 22:19:54 +03:00
if ( _log_journal & LOG_JOURNAL_COMMAND ) {
/*
* TODO : DAEMON = dmeventd | lvmpolld | lvmdbusd ,
* Could we include caller info such as libblkid , udev rule , etc ?
* Does systemd already record the caller for us ?
*/
/* The command line, pid, and other things are automatically included. */
sd_journal_send ( " MESSAGE=lvm command %s " , cmd_name ,
" MESSAGE_ID=3ca432788c374e4ba684b834188eca36 " ,
" LVM_CMD_NAME=%s " , cmd_name ,
" LVM_CMD_ID=%s " , cmd_id ,
" PRIORITY=%i " , LOG_INFO ,
NULL ) ;
}
2021-10-14 21:50:01 +03:00
# endif
2021-03-24 22:19:54 +03:00
}
uint32_t log_journal_str_to_val ( const char * str )
{
if ( ! strcasecmp ( str , " command " ) )
return LOG_JOURNAL_COMMAND ;
if ( ! strcasecmp ( str , " output " ) )
return LOG_JOURNAL_OUTPUT ;
if ( ! strcasecmp ( str , " debug " ) )
return LOG_JOURNAL_DEBUG ;
2023-07-15 11:57:37 +03:00
log_warn ( " WARNING: Ignoring unrecognized journal value. " ) ;
2021-03-24 22:19:54 +03:00
return 0 ;
}