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
*/
2009-09-15 02:57:46 +04:00
# include "configure.h"
2009-09-04 01:11:53 +04:00
# include <stdio.h>
# include <stdlib.h>
# include <stdint.h>
# include <string.h>
# include <errno.h>
# include <sched.h>
# include <sys/types.h>
# include <sys/wait.h>
# include <sys/stat.h>
# include <signal.h>
# include <unistd.h>
# include <fcntl.h>
# include <linux/types.h>
# include <sys/socket.h>
# include <linux/netlink.h>
# include <linux/dm-ioctl.h>
# include "dm-log-userspace.h"
# include "functions.h"
# include "local.h"
# include "cluster.h"
# include "common.h"
# include "logging.h"
# include "link_mon.h"
static int exit_now = 0 ;
static sigset_t signal_mask ;
static int signal_received ;
static void process_signals ( void ) ;
static void daemonize ( void ) ;
static void init_all ( void ) ;
static void cleanup_all ( void ) ;
int main ( int argc , char * argv [ ] )
{
daemonize ( ) ;
init_all ( ) ;
/* Parent can now exit, we're ready to handle requests */
kill ( getppid ( ) , SIGTERM ) ;
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
*
*/
static void parent_exit_handler ( int sig )
{
exit_now = 1 ;
}
/*
* create_lockfile - create and lock a lock file
* @ lockfile : location of lock file
*
* Returns : 0 on success , - 1 otherwise
*/
static int create_lockfile ( char * lockfile )
{
int fd ;
struct flock lock ;
char buffer [ 50 ] ;
if ( ( fd = open ( lockfile , O_CREAT | O_WRONLY ,
( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) ) ) < 0 )
return - errno ;
lock . l_type = F_WRLCK ;
lock . l_start = 0 ;
lock . l_whence = SEEK_SET ;
lock . l_len = 0 ;
if ( fcntl ( fd , F_SETLK , & lock ) < 0 ) {
close ( fd ) ;
return - errno ;
}
if ( ftruncate ( fd , 0 ) < 0 ) {
close ( fd ) ;
return - errno ;
}
sprintf ( buffer , " %d \n " , getpid ( ) ) ;
if ( write ( fd , buffer , strlen ( buffer ) ) < strlen ( buffer ) ) {
close ( fd ) ;
unlink ( lockfile ) ;
return - errno ;
}
return 0 ;
}
static void sig_handler ( int sig )
{
sigaddset ( & signal_mask , sig ) ;
+ + signal_received ;
}
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 ) ;
}
}
}
/*
* daemonize
*
* Performs the steps necessary to become a daemon .
*/
static void daemonize ( void )
{
int pid ;
int status ;
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 ( ) ;
chdir ( " / " ) ;
umask ( 0 ) ;
close ( 0 ) ; close ( 1 ) ; close ( 2 ) ;
open ( " /dev/null " , O_RDONLY ) ; /* reopen stdin */
open ( " /dev/null " , O_WRONLY ) ; /* reopen stdout */
open ( " /dev/null " , O_WRONLY ) ; /* reopen stderr */
LOG_OPEN ( " cmirrord " , LOG_PID , LOG_DAEMON ) ;
if ( create_lockfile ( CMIRRORD_PIDFILE ) )
exit ( EXIT_LOCKFILE ) ;
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 ;
}
/*
* init_all
*
* Initialize modules . Exit on failure .
*/
static void init_all ( void )
{
int r ;
if ( ( r = init_local ( ) ) | |
( r = init_cluster ( ) ) ) {
exit ( r ) ;
}
}
/*
* cleanup_all
*
* Clean up before exiting
*/
static void cleanup_all ( void )
{
cleanup_local ( ) ;
cleanup_cluster ( ) ;
}