2014-06-06 12:55:56 +10:00
/*
common system utilities
Copyright ( C ) Amitay Isaacs 2014
Copyright ( C ) Martin Schwenke 2014
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 .
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 .
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 16:50:46 +11:00
# include "replace.h"
2014-06-06 12:55:56 +10:00
# include "system/filesys.h"
2014-06-10 17:04:34 +10:00
# include "system/shmem.h"
2015-10-26 16:50:46 +11:00
# include "system/network.h"
2014-06-06 12:55:56 +10:00
2016-03-11 11:44:12 +11:00
# include <talloc.h>
2014-06-06 12:55:56 +10:00
# include <libgen.h>
2015-10-26 16:50:46 +11:00
# include "lib/util/debug.h"
2015-11-02 16:03:29 +11:00
# include "protocol/protocol.h"
2015-10-23 14:11:53 +11:00
2015-11-11 14:43:56 +11:00
# include "common/logging.h"
2015-10-23 14:11:53 +11:00
# include "common/system.h"
2014-06-06 13:52:15 +10:00
# if HAVE_SCHED_H
# include <sched.h>
# endif
# if HAVE_PROCINFO_H
# include <procinfo.h>
# endif
/*
if possible , make this task real time
*/
2014-09-12 11:22:36 +10:00
bool set_scheduler ( void )
2014-06-06 13:52:15 +10:00
{
# ifdef _AIX_
# if HAVE_THREAD_SETSCHED
struct thrdentry64 te ;
tid64_t ti ;
ti = 0ULL ;
if ( getthrds64 ( getpid ( ) , & te , sizeof ( te ) , & ti , 1 ) ! = 1 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get thread information \n " ) ) ;
2014-09-12 11:22:36 +10:00
return false ;
2014-06-06 13:52:15 +10:00
}
if ( thread_setsched ( te . ti_tid , 0 , SCHED_RR ) = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " Unable to set scheduler to SCHED_RR (%s) \n " ,
strerror ( errno ) ) ) ;
2014-09-12 11:22:36 +10:00
return false ;
2014-06-06 13:52:15 +10:00
} else {
2014-09-12 11:22:36 +10:00
return true ;
2014-06-06 13:52:15 +10:00
}
# endif
# else /* no AIX */
# if HAVE_SCHED_SETSCHEDULER
struct sched_param p ;
2014-05-31 14:01:53 +10:00
int policy = SCHED_FIFO ;
2014-06-06 13:52:15 +10:00
p . sched_priority = 1 ;
2014-05-31 14:01:53 +10:00
# ifdef SCHED_RESET_ON_FORK
policy | = SCHED_RESET_ON_FORK ;
# endif
if ( sched_setscheduler ( 0 , policy , & p ) = = - 1 ) {
2014-06-06 13:52:15 +10:00
DEBUG ( DEBUG_CRIT , ( " Unable to set scheduler to SCHED_FIFO (%s) \n " ,
strerror ( errno ) ) ) ;
2014-09-12 11:22:36 +10:00
return false ;
2014-06-06 13:52:15 +10:00
} else {
2014-09-12 11:22:36 +10:00
return true ;
2014-06-06 13:52:15 +10:00
}
# endif
# endif
2014-09-15 11:48:33 +10:00
DEBUG ( DEBUG_CRIT , ( " No way to set real-time priority. \n " ) ) ;
2014-09-12 11:22:36 +10:00
return false ;
2014-06-06 13:52:15 +10:00
}
/*
reset scheduler from real - time to normal scheduling
*/
void reset_scheduler ( void )
{
# ifdef _AIX_
# if HAVE_THREAD_SETSCHED
struct thrdentry64 te ;
tid64_t ti ;
ti = 0ULL ;
if ( getthrds64 ( getpid ( ) , & te , sizeof ( te ) , & ti , 1 ) ! = 1 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get thread information \n " ) ) ;
}
if ( thread_setsched ( te . ti_tid , 0 , SCHED_OTHER ) = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " Unable to set scheduler to SCHED_OTHER \n " ) ) ;
}
# endif
# else /* no AIX */
# if HAVE_SCHED_SETSCHEDULER
2014-05-31 14:01:53 +10:00
# ifndef SCHED_RESET_ON_FORK
2014-06-06 13:52:15 +10:00
struct sched_param p ;
p . sched_priority = 0 ;
if ( sched_setscheduler ( 0 , SCHED_OTHER , & p ) = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " Unable to set scheduler to SCHED_OTHER \n " ) ) ;
}
# endif
# endif
2014-05-31 14:01:53 +10:00
# endif
2014-06-06 13:52:15 +10:00
}
bool parse_ipv4 ( const char * s , unsigned port , struct sockaddr_in * sin )
{
sin - > sin_family = AF_INET ;
sin - > sin_port = htons ( port ) ;
if ( inet_pton ( AF_INET , s , & sin - > sin_addr ) ! = 1 ) {
DEBUG ( DEBUG_ERR , ( __location__ " Failed to translate %s into sin_addr \n " , s ) ) ;
return false ;
}
2015-02-20 11:47:23 +11:00
# ifdef HAVE_SOCK_SIN_LEN
2015-08-19 07:33:48 +02:00
sin - > sin_len = sizeof ( * sin ) ;
2015-02-20 11:47:23 +11:00
# endif
2014-06-06 13:52:15 +10:00
return true ;
}
static bool parse_ipv6 ( const char * s , const char * ifaces , unsigned port , ctdb_sock_addr * saddr )
{
saddr - > ip6 . sin6_family = AF_INET6 ;
saddr - > ip6 . sin6_port = htons ( port ) ;
saddr - > ip6 . sin6_flowinfo = 0 ;
saddr - > ip6 . sin6_scope_id = 0 ;
if ( inet_pton ( AF_INET6 , s , & saddr - > ip6 . sin6_addr ) ! = 1 ) {
DEBUG ( DEBUG_ERR , ( __location__ " Failed to translate %s into sin6_addr \n " , s ) ) ;
return false ;
}
if ( ifaces & & IN6_IS_ADDR_LINKLOCAL ( & saddr - > ip6 . sin6_addr ) ) {
if ( strchr ( ifaces , ' , ' ) ) {
DEBUG ( DEBUG_ERR , ( __location__ " Link local address %s "
" is specified for multiple ifaces %s \n " ,
s , ifaces ) ) ;
return false ;
}
saddr - > ip6 . sin6_scope_id = if_nametoindex ( ifaces ) ;
}
2015-02-20 11:47:23 +11:00
# ifdef HAVE_SOCK_SIN_LEN
saddr - > ip6 . sin6_len = sizeof ( * saddr ) ;
# endif
2014-06-06 13:52:15 +10:00
return true ;
}
/*
parse an ip
*/
bool parse_ip ( const char * addr , const char * ifaces , unsigned port , ctdb_sock_addr * saddr )
{
char * p ;
bool ret ;
ZERO_STRUCTP ( saddr ) ; /* valgrind :-) */
/* now is this a ipv4 or ipv6 address ?*/
p = index ( addr , ' : ' ) ;
if ( p = = NULL ) {
ret = parse_ipv4 ( addr , port , & saddr - > ip ) ;
} else {
ret = parse_ipv6 ( addr , ifaces , port , saddr ) ;
}
return ret ;
}
/*
parse a ip / mask pair
*/
bool parse_ip_mask ( const char * str , const char * ifaces , ctdb_sock_addr * addr , unsigned * mask )
{
char * p ;
char s [ 64 ] ; /* Much longer than INET6_ADDRSTRLEN */
char * endp = NULL ;
ssize_t len ;
bool ret ;
ZERO_STRUCT ( * addr ) ;
len = strlen ( str ) ;
if ( len > = sizeof ( s ) ) {
DEBUG ( DEBUG_ERR , ( " Address %s is unreasonably long \n " , str ) ) ;
return false ;
}
strncpy ( s , str , len + 1 ) ;
p = rindex ( s , ' / ' ) ;
if ( p = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " This addr: %s does not contain a mask \n " , s ) ) ;
return false ;
}
* mask = strtoul ( p + 1 , & endp , 10 ) ;
if ( endp = = NULL | | * endp ! = 0 ) {
/* trailing garbage */
DEBUG ( DEBUG_ERR , ( __location__ " Trailing garbage after the mask in %s \n " , s ) ) ;
return false ;
}
* p = 0 ;
/* now is this a ipv4 or ipv6 address ?*/
ret = parse_ip ( s , ifaces , 0 , addr ) ;
return ret ;
}
/*
parse a ip : port pair
*/
bool parse_ip_port ( const char * addr , ctdb_sock_addr * saddr )
{
char * p ;
char s [ 64 ] ; /* Much longer than INET6_ADDRSTRLEN */
unsigned port ;
char * endp = NULL ;
ssize_t len ;
bool ret ;
len = strlen ( addr ) ;
if ( len > = sizeof ( s ) ) {
DEBUG ( DEBUG_ERR , ( " Address %s is unreasonably long \n " , addr ) ) ;
return false ;
}
strncpy ( s , addr , len + 1 ) ;
p = rindex ( s , ' : ' ) ;
if ( p = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " This addr: %s does not contain a port number \n " , s ) ) ;
return false ;
}
port = strtoul ( p + 1 , & endp , 10 ) ;
if ( endp = = NULL | | * endp ! = 0 ) {
/* trailing garbage */
DEBUG ( DEBUG_ERR , ( __location__ " Trailing garbage after the port in %s \n " , s ) ) ;
return false ;
}
* p = 0 ;
/* now is this a ipv4 or ipv6 address ?*/
ret = parse_ip ( s , NULL , port , saddr ) ;
return ret ;
}
2014-06-10 17:04:34 +10:00
/* we don't lock future pages here; it would increase the chance that
* we ' d fail to mmap later on . */
void lockdown_memory ( bool valgrinding )
{
# if defined(HAVE_MLOCKALL) && !defined(_AIX_)
/* Extra stack, please! */
char dummy [ 10000 ] ;
memset ( dummy , 0 , sizeof ( dummy ) ) ;
if ( valgrinding ) {
return ;
}
/* Ignore when running in local daemons mode */
if ( getuid ( ) ! = 0 ) {
return ;
}
/* Avoid compiler optimizing out dummy. */
mlock ( dummy , sizeof ( dummy ) ) ;
if ( mlockall ( MCL_CURRENT ) ! = 0 ) {
DEBUG ( DEBUG_WARNING , ( " Failed to lockdown memory: %s' \n " ,
strerror ( errno ) ) ) ;
}
# endif
}
2014-06-06 12:55:56 +10:00
int mkdir_p ( const char * dir , int mode )
{
char t [ PATH_MAX ] ;
ssize_t len ;
int ret ;
if ( strcmp ( dir , " / " ) = = 0 ) {
return 0 ;
}
if ( strcmp ( dir , " . " ) = = 0 ) {
return 0 ;
}
/* Try to create directory */
ret = mkdir ( dir , mode ) ;
/* Succeed if that worked or if it already existed */
if ( ret = = 0 | | errno = = EEXIST ) {
return 0 ;
}
/* Fail on anything else except ENOENT */
if ( errno ! = ENOENT ) {
return ret ;
}
/* Create ancestors */
len = strlen ( dir ) ;
if ( len > = PATH_MAX ) {
errno = ENAMETOOLONG ;
return - 1 ;
}
strncpy ( t , dir , len + 1 ) ;
ret = mkdir_p ( dirname ( t ) , mode ) ;
if ( ret ! = 0 ) {
return ret ;
}
/* Create directory */
ret = mkdir ( dir , mode ) ;
if ( ( ret = = - 1 ) & & ( errno = = EEXIST ) ) {
ret = 0 ;
}
return ret ;
}
2014-06-06 15:25:08 +10:00
void mkdir_p_or_die ( const char * dir , int mode )
{
int ret ;
ret = mkdir_p ( dir , mode ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ALERT ,
( " ctdb exiting with error: "
" failed to create directory \" %s \" (%s) \n " ,
dir , strerror ( errno ) ) ) ;
exit ( 1 ) ;
}
}
2014-07-30 20:50:59 +10:00
/* A read wrapper that will deal with EINTR. For now, copied from
* source3 / lib / system . c
*/
ssize_t sys_read ( int fd , void * buf , size_t count )
{
ssize_t ret ;
do {
ret = read ( fd , buf , count ) ;
# if defined(EWOULDBLOCK)
} while ( ret = = - 1 & & ( errno = = EINTR | | errno = = EAGAIN | | errno = = EWOULDBLOCK ) ) ;
# else
} while ( ret = = - 1 & & ( errno = = EINTR | | errno = = EAGAIN ) ) ;
# endif
return ret ;
}
/* A write wrapper that will deal with EINTR. For now, copied from
* source3 / lib / system . c
*/
ssize_t sys_write ( int fd , const void * buf , size_t count )
{
ssize_t ret ;
do {
ret = write ( fd , buf , count ) ;
# if defined(EWOULDBLOCK)
} while ( ret = = - 1 & & ( errno = = EINTR | | errno = = EAGAIN | | errno = = EWOULDBLOCK ) ) ;
# else
} while ( ret = = - 1 & & ( errno = = EINTR | | errno = = EAGAIN ) ) ;
# endif
return ret ;
}
2015-12-08 14:12:46 +11:00
void ctdb_wait_for_process_to_exit ( pid_t pid )
{
while ( kill ( pid , 0 ) = = 0 | | errno ! = ESRCH ) {
sleep ( 5 ) ;
}
}
2016-03-11 11:44:12 +11:00
int ctdb_parse_connections ( FILE * fp , TALLOC_CTX * mem_ctx ,
int * num_conn , struct ctdb_connection * * out )
{
struct ctdb_connection * conn = NULL ;
char line [ 128 ] , src [ 128 ] , dst [ 128 ] ; /* long enough for IPv6 */
int line_num , ret ;
int num = 0 , max = 0 ;
line_num = 0 ;
while ( ! feof ( fp ) ) {
if ( fgets ( line , sizeof ( line ) , fp ) = = NULL ) {
break ;
}
line_num + = 1 ;
/* Skip empty lines */
if ( line [ 0 ] = = ' \n ' ) {
continue ;
}
ret = sscanf ( line , " %s %s \n " , src , dst ) ;
if ( ret ! = 2 ) {
DEBUG ( DEBUG_ERR , ( " Bad line [%d]: %s \n " ,
line_num , line ) ) ;
return EINVAL ;
}
if ( num > = max ) {
max + = 1024 ;
conn = talloc_realloc ( mem_ctx , conn ,
struct ctdb_connection , max ) ;
if ( conn = = NULL ) {
return ENOMEM ;
}
}
if ( ! parse_ip_port ( src , & conn [ num ] . src ) ) {
DEBUG ( DEBUG_ERR , ( " Invalid IP address %s \n " , src ) ) ;
2016-07-27 12:02:19 +10:00
talloc_free ( conn ) ;
2016-03-11 11:44:12 +11:00
return EINVAL ;
}
if ( ! parse_ip_port ( dst , & conn [ num ] . dst ) ) {
DEBUG ( DEBUG_ERR , ( " Invalid IP address %s \n " , dst ) ) ;
2016-07-27 12:02:19 +10:00
talloc_free ( conn ) ;
2016-03-11 11:44:12 +11:00
return EINVAL ;
}
num + = 1 ;
}
* num_conn = num ;
* out = conn ;
return 0 ;
}