2009-09-04 01:11:53 +04:00
/*
* Copyright ( C ) 2004 - 2009 Red Hat , Inc . All rights reserved .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU General Public License v .2 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2010-01-19 00:07:24 +03:00
# include "logging.h"
# include "common.h"
# include "functions.h"
# include "link_mon.h"
# include "local.h"
2009-09-15 02:57:46 +04:00
2015-07-08 15:41:23 +03:00
# include <getopt.h>
2009-09-04 01:11:53 +04:00
# include <errno.h>
# include <fcntl.h>
# include <sys/socket.h>
2010-03-29 18:05:17 +04:00
# include <sys/stat.h>
2010-01-19 00:07:24 +03:00
# include <sys/wait.h>
# include <unistd.h>
2009-09-04 01:11:53 +04:00
2010-01-19 18:58:45 +03:00
static volatile sig_atomic_t exit_now = 0 ;
/* FIXME Review signal handling. Should be volatile sig_atomic_t */
2009-09-04 01:11:53 +04:00
static sigset_t signal_mask ;
2010-01-19 18:58:45 +03:00
static volatile sig_atomic_t signal_received ;
2009-09-04 01:11:53 +04:00
static void process_signals ( void ) ;
static void daemonize ( void ) ;
static void init_all ( void ) ;
static void cleanup_all ( void ) ;
2015-07-08 15:41:23 +03:00
static void usage ( FILE * dest )
2009-09-04 01:11:53 +04:00
{
2015-07-08 15:41:23 +03:00
fprintf ( dest , " Usage: cmirrord [options] \n "
" -f, --foreground stay in the foreground, log to the terminal \n "
" -h, --help print this help \n " ) ;
}
int main ( int argc , char * argv [ ] )
{
int foreground_mode = 0 ;
struct option longopts [ ] = {
{ " foreground " , no_argument , NULL , ' f ' } ,
{ " help " , no_argument , NULL , ' h ' } ,
{ 0 , 0 , 0 , 0 }
} ;
int opt ;
while ( ( opt = getopt_long ( argc , argv , " fh " , longopts , NULL ) ) ! = - 1 ) {
switch ( opt ) {
case ' f ' :
foreground_mode = 1 ;
break ;
case ' h ' :
usage ( stdout ) ;
exit ( 0 ) ;
default :
usage ( stderr ) ;
exit ( 2 ) ;
}
}
if ( optind < argc ) {
usage ( stderr ) ;
exit ( 2 ) ;
}
if ( ! foreground_mode )
daemonize ( ) ;
2009-09-04 01:11:53 +04:00
init_all ( ) ;
/* Parent can now exit, we're ready to handle requests */
2015-07-08 15:41:23 +03:00
if ( ! foreground_mode )
kill ( getppid ( ) , SIGTERM ) ;
2009-09-04 01:11:53 +04:00
LOG_PRINT ( " Starting cmirrord: " ) ;
LOG_PRINT ( " Built: " __DATE__ " " __TIME__ " \n " ) ;
LOG_DBG ( " Compiled with debugging. " ) ;
while ( ! exit_now ) {
links_monitor ( ) ;
links_issue_callbacks ( ) ;
process_signals ( ) ;
}
exit ( EXIT_SUCCESS ) ;
}
/*
* parent_exit_handler : exit the parent
* @ sig : the signal
*
*/
2010-07-09 19:34:40 +04:00
static void parent_exit_handler ( int sig __attribute__ ( ( unused ) ) )
2009-09-04 01:11:53 +04:00
{
exit_now = 1 ;
}
static void sig_handler ( int sig )
{
2010-01-19 18:58:45 +03:00
/* FIXME Races - don't touch signal_mask here. */
2009-09-04 01:11:53 +04:00
sigaddset ( & signal_mask , sig ) ;
2010-01-19 18:58:45 +03:00
signal_received = 1 ;
2009-09-04 01:11:53 +04:00
}
static void process_signal ( int sig ) {
int r = 0 ;
switch ( sig ) {
case SIGINT :
case SIGQUIT :
case SIGTERM :
case SIGHUP :
r + = log_status ( ) ;
break ;
case SIGUSR1 :
case SIGUSR2 :
log_debug ( ) ;
/*local_debug();*/
cluster_debug ( ) ;
return ;
default :
LOG_PRINT ( " Unknown signal received... ignoring " ) ;
return ;
}
if ( ! r ) {
LOG_DBG ( " No current cluster logs... safe to exit. " ) ;
cleanup_all ( ) ;
exit ( EXIT_SUCCESS ) ;
}
LOG_ERROR ( " Cluster logs exist. Refusing to exit. " ) ;
}
static void process_signals ( void )
{
int x ;
if ( ! signal_received )
return ;
signal_received = 0 ;
for ( x = 1 ; x < _NSIG ; x + + ) {
if ( sigismember ( & signal_mask , x ) ) {
sigdelset ( & signal_mask , x ) ;
process_signal ( x ) ;
}
}
}
2010-07-13 17:51:01 +04:00
static void remove_lockfile ( void )
{
2011-09-06 22:11:21 +04:00
if ( unlink ( CMIRRORD_PIDFILE ) )
LOG_ERROR ( " Unable to remove \" " CMIRRORD_PIDFILE " \" %s " , strerror ( errno ) ) ;
2010-07-13 17:51:01 +04:00
}
2009-09-04 01:11:53 +04:00
/*
* daemonize
*
* Performs the steps necessary to become a daemon .
*/
static void daemonize ( void )
{
int pid ;
int status ;
2011-09-21 14:42:53 +04:00
int devnull ;
if ( ( devnull = open ( " /dev/null " , O_RDWR ) ) = = - 1 ) {
LOG_ERROR ( " Can't open /dev/null: %s " , strerror ( errno ) ) ;
exit ( EXIT_FAILURE ) ;
}
2009-09-04 01:11:53 +04:00
signal ( SIGTERM , & parent_exit_handler ) ;
pid = fork ( ) ;
if ( pid < 0 ) {
LOG_ERROR ( " Unable to fork() " ) ;
exit ( EXIT_FAILURE ) ;
}
if ( pid ) {
/* Parent waits here for child to get going */
while ( ! waitpid ( pid , & status , WNOHANG ) & & ! exit_now ) ;
if ( exit_now )
exit ( EXIT_SUCCESS ) ;
switch ( WEXITSTATUS ( status ) ) {
case EXIT_LOCKFILE :
LOG_ERROR ( " Failed to create lockfile " ) ;
LOG_ERROR ( " Process already running? " ) ;
break ;
case EXIT_KERNEL_SOCKET :
LOG_ERROR ( " Unable to create netlink socket " ) ;
break ;
case EXIT_KERNEL_BIND :
LOG_ERROR ( " Unable to bind to netlink socket " ) ;
break ;
case EXIT_KERNEL_SETSOCKOPT :
LOG_ERROR ( " Unable to setsockopt on netlink socket " ) ;
break ;
case EXIT_CLUSTER_CKPT_INIT :
LOG_ERROR ( " Unable to initialize checkpoint service " ) ;
LOG_ERROR ( " Has the cluster infrastructure been started? " ) ;
break ;
case EXIT_FAILURE :
LOG_ERROR ( " Failed to start: Generic error " ) ;
break ;
default :
LOG_ERROR ( " Failed to start: Unknown error " ) ;
break ;
}
exit ( EXIT_FAILURE ) ;
}
setsid ( ) ;
2012-06-20 02:10:40 +04:00
if ( chdir ( " / " ) ) {
LOG_ERROR ( " Failed to chdir /: %s " , strerror ( errno ) ) ;
exit ( EXIT_FAILURE ) ;
}
2009-09-04 01:11:53 +04:00
umask ( 0 ) ;
2011-09-21 14:42:53 +04:00
if ( close ( 0 ) | | close ( 1 ) | | close ( 2 ) ) {
LOG_ERROR ( " Failed to close terminal FDs " ) ;
exit ( EXIT_FAILURE ) ;
}
if ( ( dup2 ( devnull , 0 ) < 0 ) | | /* reopen stdin */
( dup2 ( devnull , 1 ) < 0 ) | | /* reopen stdout */
( dup2 ( devnull , 2 ) < 0 ) ) /* reopen stderr */
exit ( EXIT_FAILURE ) ;
2009-09-04 01:11:53 +04:00
2013-08-06 18:08:31 +04:00
if ( ( devnull > STDERR_FILENO ) & & close ( devnull ) ) {
LOG_ERROR ( " Failed to close descriptor %d: %s " ,
devnull , strerror ( errno ) ) ;
exit ( EXIT_FAILURE ) ;
}
2009-09-04 01:11:53 +04:00
LOG_OPEN ( " cmirrord " , LOG_PID , LOG_DAEMON ) ;
2015-07-08 15:41:22 +03:00
}
/*
* init_all
*
* Initialize modules . Exit on failure .
*/
static void init_all ( void )
{
int r ;
2009-09-04 01:11:53 +04:00
2010-12-13 13:43:56 +03:00
( void ) dm_prepare_selinux_context ( CMIRRORD_PIDFILE , S_IFREG ) ;
2010-07-13 17:51:01 +04:00
if ( dm_create_lockfile ( CMIRRORD_PIDFILE ) = = 0 )
2009-09-04 01:11:53 +04:00
exit ( EXIT_LOCKFILE ) ;
2010-12-13 13:43:56 +03:00
( void ) dm_prepare_selinux_context ( NULL , 0 ) ;
2009-09-04 01:11:53 +04:00
2010-07-13 17:51:01 +04:00
atexit ( remove_lockfile ) ;
2010-01-19 18:58:45 +03:00
/* FIXME Replace with sigaction. (deprecated) */
2009-09-04 01:11:53 +04:00
signal ( SIGINT , & sig_handler ) ;
signal ( SIGQUIT , & sig_handler ) ;
signal ( SIGTERM , & sig_handler ) ;
signal ( SIGHUP , & sig_handler ) ;
signal ( SIGPIPE , SIG_IGN ) ;
signal ( SIGUSR1 , & sig_handler ) ;
signal ( SIGUSR2 , & sig_handler ) ;
sigemptyset ( & signal_mask ) ;
signal_received = 0 ;
if ( ( r = init_local ( ) ) | |
( r = init_cluster ( ) ) ) {
exit ( r ) ;
}
}
/*
* cleanup_all
*
* Clean up before exiting
*/
static void cleanup_all ( void )
{
cleanup_local ( ) ;
cleanup_cluster ( ) ;
}