|
|
|
#include "Daemon.h"
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
|
|
|
|
#include <signal.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <thread>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include "Config.h"
|
|
|
|
#include "FS.h"
|
|
|
|
#include "Log.h"
|
|
|
|
#include "RouterContext.h"
|
|
|
|
#include "ClientContext.h"
|
|
|
|
|
|
|
|
void handle_signal(int sig)
|
|
|
|
{
|
|
|
|
switch (sig)
|
|
|
|
{
|
|
|
|
case SIGHUP:
|
|
|
|
LogPrint(eLogInfo, "Daemon: Got SIGHUP, reopening log...");
|
|
|
|
i2p::log::Logger().Reopen ();
|
|
|
|
i2p::client::context.ReloadConfig();
|
|
|
|
break;
|
|
|
|
case SIGINT:
|
|
|
|
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;
|
|
|
|
break;
|
|
|
|
case SIGABRT:
|
|
|
|
case SIGTERM:
|
|
|
|
Daemon.running = 0; // Exit loop
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace i2p
|
|
|
|
{
|
|
|
|
namespace util
|
|
|
|
{
|
|
|
|
bool DaemonLinux::start()
|
|
|
|
{
|
|
|
|
if (isDaemon)
|
|
|
|
{
|
|
|
|
pid_t pid;
|
|
|
|
pid = fork();
|
|
|
|
if (pid > 0) // parent
|
|
|
|
::exit (EXIT_SUCCESS);
|
|
|
|
|
|
|
|
if (pid < 0) // error
|
|
|
|
{
|
|
|
|
LogPrint(eLogError, "Daemon: could not fork: ", strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// child
|
|
|
|
umask(S_IWGRP | S_IRWXO); // 0027
|
|
|
|
int sid = setsid();
|
|
|
|
if (sid < 0)
|
|
|
|
{
|
|
|
|
LogPrint(eLogError, "Daemon: could not create process group.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
std::string d = i2p::fs::GetDataDir();
|
|
|
|
if (chdir(d.c_str()) != 0)
|
|
|
|
{
|
|
|
|
LogPrint(eLogError, "Daemon: could not chdir: ", strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// point std{in,out,err} descriptors to /dev/null
|
|
|
|
stdin = freopen("/dev/null", "r", stdin);
|
|
|
|
stdout = freopen("/dev/null", "w", stdout);
|
|
|
|
stderr = freopen("/dev/null", "w", stderr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pidfile
|
|
|
|
// this code is c-styled and a bit ugly, but we need fd for locking pidfile
|
|
|
|
std::string pidfile; i2p::config::GetOption("pidfile", pidfile);
|
|
|
|
if (pidfile == "") {
|
|
|
|
pidfile = i2p::fs::DataDirPath("i2pd.pid");
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
if (lockf(pidFH, F_TLOCK, 0) != 0)
|
|
|
|
{
|
|
|
|
LogPrint(eLogError, "Daemon: could not lock pid file ", pidfile, ": ", strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
char pid[10];
|
|
|
|
sprintf(pid, "%d\n", getpid());
|
|
|
|
ftruncate(pidFH, 0);
|
|
|
|
if (write(pidFH, pid, strlen(pid)) < 0)
|
|
|
|
{
|
|
|
|
LogPrint(eLogError, "Daemon: could not write pidfile: ", strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
gracefullShutdownInterval = 0; // not specified
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
return Daemon_Singleton::start();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DaemonLinux::stop()
|
|
|
|
{
|
|
|
|
i2p::fs::Remove(pidfile);
|
|
|
|
|
|
|
|
return Daemon_Singleton::stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DaemonLinux::run ()
|
|
|
|
{
|
|
|
|
while (running)
|
|
|
|
{
|
|
|
|
std::this_thread::sleep_for (std::chrono::seconds(1));
|
|
|
|
if (gracefullShutdownInterval)
|
|
|
|
{
|
|
|
|
gracefullShutdownInterval--; // - 1 second
|
|
|
|
if (gracefullShutdownInterval <= 0)
|
|
|
|
{
|
|
|
|
LogPrint(eLogInfo, "Graceful shutdown");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|