2014-08-08 14:54:54 +04:00
/*
2008-01-16 14:03:01 +03:00
ctdb logging code
Copyright ( C ) Andrew Tridgell 2008
This program 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 3 of the License , or
( at your option ) any later version .
2014-08-08 14:54:54 +04:00
2008-01-16 14:03:01 +03:00
This program 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 .
2014-08-08 14:54:54 +04:00
2008-01-16 14:03:01 +03:00
You should have received a copy of the GNU General Public License
along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*/
2015-10-26 08:50:46 +03:00
# include "replace.h"
# include "system/filesys.h"
# include "system/network.h"
2008-01-16 14:03:01 +03:00
# include "system/time.h"
2015-10-26 08:50:46 +03:00
# include <talloc.h>
# include <tevent.h>
2014-08-11 11:07:41 +04:00
# include "lib/util/dlinklist.h"
2015-10-26 08:50:46 +03:00
# include "lib/util/debug.h"
2016-05-27 06:50:06 +03:00
# include "lib/util/blocking.h"
2016-11-29 04:55:06 +03:00
# include "lib/util/sys_rw.h"
2016-09-15 09:10:49 +03:00
# include "lib/util/time.h"
2015-10-26 08:50:46 +03:00
# include "ctdb_private.h"
# include "ctdb_client.h"
2015-10-23 06:17:34 +03:00
# include "common/common.h"
2015-11-11 07:41:10 +03:00
# include "common/logging.h"
2014-08-11 11:07:41 +04:00
2008-01-16 14:03:01 +03:00
struct ctdb_log_state {
2011-08-26 03:39:25 +04:00
const char * prefix ;
2008-01-16 14:03:01 +03:00
int fd , pfd ;
char buf [ 1024 ] ;
uint16_t buf_used ;
2009-12-08 05:14:30 +03:00
void ( * logfn ) ( const char * , uint16_t , void * ) ;
void * logfn_private ;
2008-01-16 14:03:01 +03:00
} ;
2014-08-11 11:07:41 +04:00
/* Used by ctdb_set_child_logging() */
2008-01-16 14:03:01 +03:00
static struct ctdb_log_state * log_state ;
2014-08-11 11:07:41 +04:00
/* Initialise logging */
2016-11-30 08:46:19 +03:00
bool ctdb_logging_init ( TALLOC_CTX * mem_ctx , const char * logging ,
const char * debug_level )
2008-01-16 14:03:01 +03:00
{
2009-05-20 14:08:13 +04:00
int ret ;
2009-10-30 10:53:17 +03:00
2014-10-16 13:03:51 +04:00
log_state = talloc_zero ( mem_ctx , struct ctdb_log_state ) ;
2014-08-08 05:50:37 +04:00
if ( log_state = = NULL ) {
2016-11-29 08:36:57 +03:00
return false ;
2009-05-20 13:47:34 +04:00
}
2008-01-16 14:03:01 +03:00
2016-11-30 08:46:19 +03:00
ret = logging_init ( mem_ctx , logging , debug_level , " ctdbd " ) ;
2016-11-29 08:36:57 +03:00
if ( ret ! = 0 ) {
return false ;
2008-01-16 14:03:01 +03:00
}
2014-08-11 11:07:41 +04:00
2016-11-29 08:36:57 +03:00
return true ;
2008-01-16 14:03:01 +03:00
}
2009-12-08 05:14:30 +03:00
/* Note that do_debug always uses the global log state. */
static void write_to_log ( struct ctdb_log_state * log ,
const char * buf , unsigned int len )
{
2014-09-24 11:12:56 +04:00
if ( script_log_level < = DEBUGLEVEL ) {
2011-08-26 03:39:25 +04:00
if ( log ! = NULL & & log - > prefix ! = NULL ) {
2014-08-19 06:15:31 +04:00
dbgtext ( " %s: %*.*s \n " , log - > prefix , len , len , buf ) ;
2011-08-26 03:39:25 +04:00
} else {
2014-08-19 06:15:31 +04:00
dbgtext ( " %*.*s \n " , len , len , buf ) ;
2011-08-26 03:39:25 +04:00
}
2009-12-08 05:14:30 +03:00
/* log it in the eventsystem as well */
2013-11-11 05:39:27 +04:00
if ( log & & log - > logfn ) {
2009-12-08 05:14:30 +03:00
log - > logfn ( log - > buf , len , log - > logfn_private ) ;
2013-11-11 05:39:27 +04:00
}
2009-12-08 05:14:30 +03:00
}
}
2008-01-16 14:03:01 +03:00
/*
called when log data comes in from a child process
*/
2015-10-26 08:50:09 +03:00
static void ctdb_child_log_handler ( struct tevent_context * ev ,
struct tevent_fd * fde ,
2014-08-08 05:42:51 +04:00
uint16_t flags , void * private )
2008-01-16 14:03:01 +03:00
{
2009-12-07 17:01:29 +03:00
struct ctdb_log_state * log = talloc_get_type ( private , struct ctdb_log_state ) ;
2008-01-16 14:03:01 +03:00
char * p ;
2008-07-23 09:25:52 +04:00
int n ;
2008-01-16 14:03:01 +03:00
2015-10-26 08:50:09 +03:00
if ( ! ( flags & TEVENT_FD_READ ) ) {
2008-01-16 14:03:01 +03:00
return ;
}
2011-08-26 03:39:25 +04:00
2014-07-30 15:03:53 +04:00
n = sys_read ( log - > pfd , & log - > buf [ log - > buf_used ] ,
2009-12-07 17:01:29 +03:00
sizeof ( log - > buf ) - log - > buf_used ) ;
2008-07-23 09:25:52 +04:00
if ( n > 0 ) {
2009-12-07 17:01:29 +03:00
log - > buf_used + = n ;
2009-12-15 02:23:58 +03:00
} else if ( n = = 0 ) {
2009-12-15 11:04:52 +03:00
if ( log ! = log_state ) {
talloc_free ( log ) ;
}
2009-12-15 02:23:58 +03:00
return ;
2008-01-16 14:03:01 +03:00
}
2009-12-07 17:01:29 +03:00
while ( log - > buf_used > 0 & &
( p = memchr ( log - > buf , ' \n ' , log - > buf_used ) ) ! = NULL ) {
int n1 = ( p - log - > buf ) + 1 ;
2008-07-23 09:25:52 +04:00
int n2 = n1 - 1 ;
/* swallow \r from child processes */
2009-12-07 17:01:29 +03:00
if ( n2 > 0 & & log - > buf [ n2 - 1 ] = = ' \r ' ) {
2008-07-23 09:25:52 +04:00
n2 - - ;
2008-01-16 15:06:37 +03:00
}
2009-12-08 05:14:30 +03:00
write_to_log ( log , log - > buf , n2 ) ;
2009-12-07 17:01:29 +03:00
memmove ( log - > buf , p + 1 , sizeof ( log - > buf ) - n1 ) ;
log - > buf_used - = n1 ;
2008-01-16 14:03:01 +03:00
}
2008-07-23 09:25:52 +04:00
/* the buffer could have completely filled - unfortunately we have
no choice but to dump it out straight away */
2009-12-07 17:01:29 +03:00
if ( log - > buf_used = = sizeof ( log - > buf ) ) {
2009-12-08 05:14:30 +03:00
write_to_log ( log , log - > buf , log - > buf_used ) ;
2009-12-07 17:01:29 +03:00
log - > buf_used = 0 ;
2008-01-16 14:40:01 +03:00
}
2008-01-16 14:03:01 +03:00
}
/*
setup for logging of child process stdout
*/
int ctdb_set_child_logging ( struct ctdb_context * ctdb )
{
int p [ 2 ] ;
2010-01-07 15:29:09 +03:00
int old_stdout , old_stderr ;
2010-08-18 03:46:31 +04:00
struct tevent_fd * fde ;
2008-01-16 14:03:01 +03:00
/* setup a pipe to catch IO from subprocesses */
if ( pipe ( p ) ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " Failed to setup for child logging pipe \n " ) ) ;
2008-01-16 14:03:01 +03:00
return - 1 ;
}
2010-01-07 15:29:09 +03:00
/* We'll fail if stderr/stdout not already open; it's simpler. */
old_stdout = dup ( STDOUT_FILENO ) ;
2016-08-05 09:50:58 +03:00
if ( old_stdout < 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to dup stdout for child logging \n " ) ) ;
return - 1 ;
}
2010-01-07 15:29:09 +03:00
old_stderr = dup ( STDERR_FILENO ) ;
2016-08-05 09:50:58 +03:00
if ( old_stderr < 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to dup stderr for child logging \n " ) ) ;
close ( old_stdout ) ;
2011-08-10 19:53:56 +04:00
return - 1 ;
}
2010-01-07 15:29:09 +03:00
if ( dup2 ( p [ 1 ] , STDOUT_FILENO ) < 0 | | dup2 ( p [ 1 ] , STDERR_FILENO ) < 0 ) {
int saved_errno = errno ;
dup2 ( old_stdout , STDOUT_FILENO ) ;
dup2 ( old_stderr , STDERR_FILENO ) ;
close ( old_stdout ) ;
close ( old_stderr ) ;
close ( p [ 0 ] ) ;
close ( p [ 1 ] ) ;
errno = saved_errno ;
printf ( __location__ " dup2 failed: %s \n " ,
strerror ( errno ) ) ;
return - 1 ;
}
close ( p [ 1 ] ) ;
close ( old_stdout ) ;
close ( old_stderr ) ;
2015-10-26 08:50:09 +03:00
fde = tevent_add_fd ( ctdb - > ev , log_state , p [ 0 ] , TEVENT_FD_READ ,
ctdb_child_log_handler , log_state ) ;
2010-08-18 03:46:31 +04:00
tevent_fd_set_auto_close ( fde ) ;
2014-08-08 05:50:37 +04:00
log_state - > pfd = p [ 0 ] ;
2008-01-16 14:03:01 +03:00
2010-02-03 22:37:41 +03:00
DEBUG ( DEBUG_DEBUG , ( __location__ " Created PIPE FD:%d for logging \n " , p [ 0 ] ) ) ;
2009-10-15 04:24:54 +04:00
2008-01-16 14:03:01 +03:00
return 0 ;
}