2014-04-20 01:54:34 +00:00
# include "Daemon.h"
# ifndef _WIN32
# include <signal.h>
# include <stdlib.h>
2016-03-08 20:02:32 +00:00
# include <thread>
2014-04-20 01:54:34 +00:00
# include <unistd.h>
2014-04-22 22:37:24 +00:00
# include <fcntl.h>
# include <sys/stat.h>
2014-04-20 01:54:34 +00:00
2016-01-20 00:00:00 +00:00
# include "Config.h"
2016-02-11 00:00:00 +00:00
# include "FS.h"
2014-04-22 22:37:24 +00:00
# include "Log.h"
2016-03-29 16:50:34 +00:00
# include "RouterContext.h"
2014-04-22 04:15:07 +00:00
2014-04-20 01:54:34 +00:00
void handle_signal ( int sig )
{
switch ( sig )
{
2016-03-29 16:34:53 +00:00
case SIGHUP :
LogPrint ( eLogInfo , " Daemon: Got SIGHUP, reopening log... " ) ;
i2p : : log : : Logger ( ) . Reopen ( ) ;
break ;
case SIGINT :
2016-03-30 01:37:30 +00:00
if ( i2p : : context . AcceptsTunnels ( ) & & ! Daemon . gracefullShutdownInterval )
{
i2p : : context . SetAcceptsTunnels ( false ) ;
Daemon . gracefullShutdownInterval = 10 * 60 ; // 10 minutes
LogPrint ( eLogInfo , " Graceful shutdown after " , Daemon . gracefullShutdownInterval , " seconds " ) ;
}
else
Daemon . running = 0 ;
2016-03-29 16:34:53 +00:00
break ;
case SIGABRT :
case SIGTERM :
Daemon . running = 0 ; // Exit loop
2014-04-20 01:54:34 +00:00
break ;
}
}
namespace i2p
{
namespace util
{
bool DaemonLinux : : start ( )
{
2016-06-01 00:00:00 +00:00
if ( isDaemon )
2014-04-20 01:54:34 +00:00
{
pid_t pid ;
pid = fork ( ) ;
2014-07-02 17:48:45 +00:00
if ( pid > 0 ) // parent
: : exit ( EXIT_SUCCESS ) ;
2014-04-20 01:54:34 +00:00
2014-07-02 17:48:45 +00:00
if ( pid < 0 ) // error
2016-01-11 10:55:18 +00:00
{
LogPrint ( eLogError , " Daemon: could not fork: " , strerror ( errno ) ) ;
2014-07-02 17:48:45 +00:00
return false ;
2016-01-11 10:55:18 +00:00
}
2014-07-02 17:48:45 +00:00
// child
2016-01-11 10:55:50 +00:00
umask ( S_IWGRP | S_IRWXO ) ; // 0027
2014-04-20 01:54:34 +00:00
int sid = setsid ( ) ;
if ( sid < 0 )
{
2015-12-18 12:25:48 +00:00
LogPrint ( eLogError , " Daemon: could not create process group. " ) ;
2014-07-02 17:48:45 +00:00
return false ;
2014-04-20 01:54:34 +00:00
}
2016-02-11 00:00:00 +00:00
std : : string d = i2p : : fs : : GetDataDir ( ) ;
2016-01-11 11:30:19 +00:00
if ( chdir ( d . c_str ( ) ) ! = 0 )
{
LogPrint ( eLogError , " Daemon: could not chdir: " , strerror ( errno ) ) ;
return false ;
}
2014-07-02 17:48:45 +00:00
2016-06-01 00:00:00 +00:00
// point std{in,out,err} descriptors to /dev/null
2016-06-14 00:52:17 +00:00
# ifndef ANDROID
stdin = freopen ( " /dev/null " , " r " , stdin ) ;
2016-06-01 00:00:00 +00:00
stdout = freopen ( " /dev/null " , " w " , stdout ) ;
stderr = freopen ( " /dev/null " , " w " , stderr ) ;
2016-06-14 00:52:17 +00:00
# endif
2014-04-20 01:54:34 +00:00
}
// Pidfile
2016-01-11 10:58:39 +00:00
// this code is c-styled and a bit ugly, but we need fd for locking pidfile
2016-01-20 00:00:00 +00:00
std : : string pidfile ; i2p : : config : : GetOption ( " pidfile " , pidfile ) ;
2016-01-12 23:31:01 +00:00
if ( pidfile = = " " ) {
2016-02-11 00:00:00 +00:00
pidfile = i2p : : fs : : DataDirPath ( " i2pd.pid " ) ;
2016-01-12 23:31:01 +00:00
}
2016-01-11 10:58:39 +00:00
if ( pidfile ! = " " ) {
pidFH = open ( pidfile . c_str ( ) , O_RDWR | O_CREAT , 0600 ) ;
if ( pidFH < 0 )
{
LogPrint ( eLogError , " Daemon: could not create pid file " , pidfile , " : " , strerror ( errno ) ) ;
return false ;
}
2016-06-14 00:52:17 +00:00
# ifndef ANDROID
2016-01-11 10:58:39 +00:00
if ( lockf ( pidFH , F_TLOCK , 0 ) ! = 0 )
2016-06-14 00:52:17 +00:00
# else
//TODO ANDROID actually need to read man for this, blindly took a solution from <https://forum.qt.io/topic/27872/qtjsondb-build-failed-for-android/2>. -anon5
if ( fcntl ( pidFH , 1 , 0 ) < 0 )
# endif
2016-01-11 10:58:39 +00:00
{
LogPrint ( eLogError , " Daemon: could not lock pid file " , pidfile , " : " , strerror ( errno ) ) ;
return false ;
}
char pid [ 10 ] ;
sprintf ( pid , " %d \n " , getpid ( ) ) ;
ftruncate ( pidFH , 0 ) ;
2016-01-11 11:30:19 +00:00
if ( write ( pidFH , pid , strlen ( pid ) ) < 0 )
{
LogPrint ( eLogError , " Daemon: could not write pidfile: " , strerror ( errno ) ) ;
return false ;
}
2014-04-20 01:54:34 +00:00
}
2016-03-29 16:34:53 +00:00
gracefullShutdownInterval = 0 ; // not specified
2014-04-20 01:54:34 +00:00
// Signal handler
struct sigaction sa ;
sa . sa_handler = handle_signal ;
sigemptyset ( & sa . sa_mask ) ;
sa . sa_flags = SA_RESTART ;
sigaction ( SIGHUP , & sa , 0 ) ;
sigaction ( SIGABRT , & sa , 0 ) ;
sigaction ( SIGTERM , & sa , 0 ) ;
sigaction ( SIGINT , & sa , 0 ) ;
2014-04-22 04:15:07 +00:00
return Daemon_Singleton : : start ( ) ;
2014-04-20 01:54:34 +00:00
}
bool DaemonLinux : : stop ( )
{
2016-02-11 00:00:00 +00:00
i2p : : fs : : Remove ( pidfile ) ;
2014-04-20 01:54:34 +00:00
2014-07-02 17:48:45 +00:00
return Daemon_Singleton : : stop ( ) ;
2014-04-20 01:54:34 +00:00
}
2016-03-08 20:02:32 +00:00
void DaemonLinux : : run ( )
{
while ( running )
{
std : : this_thread : : sleep_for ( std : : chrono : : seconds ( 1 ) ) ;
2016-03-29 16:34:53 +00:00
if ( gracefullShutdownInterval )
{
gracefullShutdownInterval - - ; // - 1 second
if ( gracefullShutdownInterval < = 0 )
{
LogPrint ( eLogInfo , " Graceful shutdown " ) ;
return ;
}
}
2016-03-08 20:02:32 +00:00
}
}
2014-04-20 01:54:34 +00:00
}
}
2014-04-22 04:15:07 +00:00
# endif