|
|
|
|
@ -96,7 +96,6 @@ Daemon::Daemon(int & argc, char * argv[]) :
|
|
|
|
|
m_boosterPid(0),
|
|
|
|
|
m_socketManager(new SocketManager),
|
|
|
|
|
m_singleInstance(new SingleInstance),
|
|
|
|
|
m_reExec(false),
|
|
|
|
|
m_notifySystemd(false),
|
|
|
|
|
m_booster(0)
|
|
|
|
|
{
|
|
|
|
|
@ -125,21 +124,16 @@ Daemon::Daemon(int & argc, char * argv[]) :
|
|
|
|
|
// Parse arguments
|
|
|
|
|
parseArgs(ArgVect(argv, argv + argc));
|
|
|
|
|
|
|
|
|
|
if (m_reExec)
|
|
|
|
|
{
|
|
|
|
|
restoreState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Store arguments list
|
|
|
|
|
m_initialArgv = argv;
|
|
|
|
|
m_initialArgc = argc;
|
|
|
|
|
|
|
|
|
|
if (!m_reExec && socketpair(AF_UNIX, SOCK_DGRAM, 0, m_boosterLauncherSocket) == -1)
|
|
|
|
|
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, m_boosterLauncherSocket) == -1)
|
|
|
|
|
{
|
|
|
|
|
throw std::runtime_error("Daemon: Creating a socket pair for boosters failed!\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!m_reExec && pipe(m_sigPipeFd) == -1)
|
|
|
|
|
if (pipe(m_sigPipeFd) == -1)
|
|
|
|
|
{
|
|
|
|
|
throw std::runtime_error("Daemon: Creating a pipe for Unix signals failed!\n");
|
|
|
|
|
}
|
|
|
|
|
@ -167,22 +161,13 @@ void Daemon::run(Booster *booster)
|
|
|
|
|
// dlopen single-instance
|
|
|
|
|
loadSingleInstancePlugin();
|
|
|
|
|
|
|
|
|
|
if (m_reExec)
|
|
|
|
|
{
|
|
|
|
|
// Reap dead booster processes and restart them
|
|
|
|
|
// Note: this cannot be done before booster plugins have been loaded
|
|
|
|
|
reapZombies();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Create socket for the booster
|
|
|
|
|
Logger::logDebug("Daemon: initing socket: %s", booster->boosterType().c_str());
|
|
|
|
|
m_socketManager->initSocket(booster->boosterType());
|
|
|
|
|
// Create socket for the booster
|
|
|
|
|
Logger::logDebug("Daemon: initing socket: %s", booster->boosterType().c_str());
|
|
|
|
|
m_socketManager->initSocket(booster->boosterType());
|
|
|
|
|
|
|
|
|
|
// Fork each booster for the first time
|
|
|
|
|
Logger::logDebug("Daemon: forking booster: %s", booster->boosterType().c_str());
|
|
|
|
|
forkBooster();
|
|
|
|
|
}
|
|
|
|
|
// Fork each booster for the first time
|
|
|
|
|
Logger::logDebug("Daemon: forking booster: %s", booster->boosterType().c_str());
|
|
|
|
|
forkBooster();
|
|
|
|
|
|
|
|
|
|
// Notify systemd that init is done
|
|
|
|
|
if (m_notifySystemd) {
|
|
|
|
|
@ -251,14 +236,6 @@ void Daemon::run(Booster *booster)
|
|
|
|
|
Logger::logDebug("Daemon: SIGPIPE received.");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SIGHUP:
|
|
|
|
|
Logger::logDebug("Daemon: SIGHUP received.");
|
|
|
|
|
reExec();
|
|
|
|
|
|
|
|
|
|
// not reached if re-exec successful
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
@ -600,10 +577,6 @@ void Daemon::parseArgs(const ArgVect & args)
|
|
|
|
|
{
|
|
|
|
|
usage(args[0].c_str(), EXIT_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
else if ((*i) == "--re-exec")
|
|
|
|
|
{
|
|
|
|
|
m_reExec = true;
|
|
|
|
|
}
|
|
|
|
|
else if ((*i) == "--systemd")
|
|
|
|
|
{
|
|
|
|
|
m_notifySystemd = true;
|
|
|
|
|
@ -727,257 +700,3 @@ Daemon::~Daemon()
|
|
|
|
|
Logger::closeLog();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Daemon::reExec()
|
|
|
|
|
{
|
|
|
|
|
Logger::logInfo("Daemon: Re-exec requested.");
|
|
|
|
|
|
|
|
|
|
struct stat st;
|
|
|
|
|
if (stat(m_stateDir.c_str(), &st) != 0)
|
|
|
|
|
{
|
|
|
|
|
Logger::logDebug("Daemon: State saving directory %s does not exist", m_stateDir.c_str());
|
|
|
|
|
Logger::logDebug("Daemon: Attempting to create it");
|
|
|
|
|
|
|
|
|
|
if (mkdir(m_stateDir.c_str(), S_IRUSR | S_IWUSR | S_IXUSR) != 0)
|
|
|
|
|
{
|
|
|
|
|
Logger::logDebug("Daemon: Failed to create directory, re-exec failed, exiting.");
|
|
|
|
|
_exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stat(m_stateDir.c_str(), &st) != 0)
|
|
|
|
|
{
|
|
|
|
|
Logger::logDebug("Daemon: Directory vanished, re-exec failed, exiting.");
|
|
|
|
|
_exit(1);
|
|
|
|
|
}
|
|
|
|
|
if (!S_ISDIR(st.st_mode))
|
|
|
|
|
{
|
|
|
|
|
Logger::logDebug("Daemon: %s exists but it is not a directory, re-exec failed, exiting.", m_stateDir.c_str());
|
|
|
|
|
_exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
std::ofstream ss(m_stateFile.c_str());
|
|
|
|
|
ss.exceptions (std::ifstream::failbit | std::ifstream::badbit);
|
|
|
|
|
|
|
|
|
|
// dump the pid to double check that the state file is from this process
|
|
|
|
|
ss << "my-pid " << getpid() << std::endl;
|
|
|
|
|
|
|
|
|
|
// Save debug mode first, restoring it will enable debug logging.
|
|
|
|
|
// This way we get debug output from the re-execed daemon as early
|
|
|
|
|
// as possible.
|
|
|
|
|
ss << "debug-mode " << m_debugMode << std::endl;
|
|
|
|
|
|
|
|
|
|
// The pids of the dead boosters are also passed as children, but
|
|
|
|
|
// this causes no harm.
|
|
|
|
|
for(PidVect::iterator it = m_children.begin(); it != m_children.end(); it++)
|
|
|
|
|
{
|
|
|
|
|
ss << "child " << *it << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(PidMap::iterator it = m_boosterPidToInvokerPid.begin(); it != m_boosterPidToInvokerPid.end(); it++)
|
|
|
|
|
{
|
|
|
|
|
ss << "booster-invoker-pid " << it->first << " " << it->second << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(FdMap::iterator it = m_boosterPidToInvokerFd.begin(); it != m_boosterPidToInvokerFd.end(); it++)
|
|
|
|
|
{
|
|
|
|
|
ss << "booster-invoker-fd " << it->first << " " << it->second << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ss << "booster-pid " << m_boosterPid << std::endl;
|
|
|
|
|
|
|
|
|
|
ss << "launcher-socket " << m_boosterLauncherSocket[0] << " " << m_boosterLauncherSocket[1] << std::endl;
|
|
|
|
|
|
|
|
|
|
ss << "sigpipe-fd " << m_sigPipeFd[0] << " " << m_sigPipeFd[1] << std::endl;
|
|
|
|
|
|
|
|
|
|
ss << "boot-mode " << m_bootMode << std::endl;
|
|
|
|
|
|
|
|
|
|
SocketManager::SocketHash s = m_socketManager->getState();
|
|
|
|
|
for(SocketManager::SocketHash::iterator it = s.begin(); it != s.end(); it++)
|
|
|
|
|
{
|
|
|
|
|
ss << "socket-hash " << it->first << " " << it->second << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// when the new applauncherd reads this,
|
|
|
|
|
// it knows state saving was successful.
|
|
|
|
|
ss << "end" << std::endl;
|
|
|
|
|
ss.close();
|
|
|
|
|
}
|
|
|
|
|
catch (std::ofstream::failure e)
|
|
|
|
|
{
|
|
|
|
|
Logger::logError("Daemon: Failed to save state, re-exec failed, exiting.");
|
|
|
|
|
_exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char* argv[] = { const_cast<char*>("/usr/bin/applauncherd.bin"),
|
|
|
|
|
const_cast<char*>("--re-exec"),
|
|
|
|
|
const_cast<char*>(" "),
|
|
|
|
|
NULL};
|
|
|
|
|
|
|
|
|
|
// The boosters have state which will become stale, so kill them.
|
|
|
|
|
// The dead boosters will be reaped when the re-execed applauncherd
|
|
|
|
|
// calls reapZombies after it has initialized.
|
|
|
|
|
killBoosters();
|
|
|
|
|
|
|
|
|
|
// Signal handlers are reset at exec(), so we will lose
|
|
|
|
|
// the SIGHUP handling. However, ignoring a signal is preserved
|
|
|
|
|
// over exec(), so start ignoring SIGHUP to prevent applauncherd
|
|
|
|
|
// dying if we receive multiple SIGHUPs.
|
|
|
|
|
signal(SIGHUP, SIG_IGN);
|
|
|
|
|
|
|
|
|
|
Logger::logDebug("Daemon: configuration saved succesfully, call execve() ");
|
|
|
|
|
execve(argv[0], argv, environ);
|
|
|
|
|
|
|
|
|
|
// Not reached.
|
|
|
|
|
Logger::logDebug("Daemon: Failed to execute execve(), re-exec failed, exiting.");
|
|
|
|
|
_exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Daemon::restoreState()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// We have saved state, try to restore it.
|
|
|
|
|
std::ifstream ss(m_stateFile.c_str());
|
|
|
|
|
ss.exceptions (std::ifstream::failbit | std::ifstream::badbit);
|
|
|
|
|
|
|
|
|
|
std::string token;
|
|
|
|
|
|
|
|
|
|
ss >> token;
|
|
|
|
|
|
|
|
|
|
// Bit of defensive programming. Read the pid of the process
|
|
|
|
|
// that left the state file. If it is different from my pid,
|
|
|
|
|
// then something is wrong, and we better exit.
|
|
|
|
|
if (token != "my-pid")
|
|
|
|
|
{
|
|
|
|
|
throw "Daemon: malformed state file, exiting.";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int pid;
|
|
|
|
|
ss >> pid;
|
|
|
|
|
if (pid != getpid())
|
|
|
|
|
{
|
|
|
|
|
throw "Daemon: stale state file, exiting.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Do not check for eof, instead trigger an exception
|
|
|
|
|
// if reading past end of file. When state restore is
|
|
|
|
|
// successful we read the "end" token and return from
|
|
|
|
|
// this method.
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
ss >> token;
|
|
|
|
|
|
|
|
|
|
if (token == "end")
|
|
|
|
|
{
|
|
|
|
|
// successfully restored state
|
|
|
|
|
ss.close();
|
|
|
|
|
|
|
|
|
|
// In debug mode it is better to leave the file there
|
|
|
|
|
// so it can be examined.
|
|
|
|
|
if (!m_debugMode && remove(m_stateFile.c_str()) == -1)
|
|
|
|
|
{
|
|
|
|
|
Logger::logError("Daemon: could not remove state file %s", m_stateFile.c_str());
|
|
|
|
|
}
|
|
|
|
|
Logger::logDebug("Daemon: state restore completed");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (token == "child")
|
|
|
|
|
{
|
|
|
|
|
int arg1;
|
|
|
|
|
ss >> arg1;
|
|
|
|
|
Logger::logDebug("Daemon: restored child %d", arg1);
|
|
|
|
|
m_children.push_back(arg1);
|
|
|
|
|
}
|
|
|
|
|
else if (token == "booster-invoker-pid")
|
|
|
|
|
{
|
|
|
|
|
int arg1, arg2;
|
|
|
|
|
ss >> arg1;
|
|
|
|
|
ss >> arg2;
|
|
|
|
|
Logger::logDebug("Daemon: restored m_boosterPidToInvokerPid[%d] = %d", arg1, arg2);
|
|
|
|
|
m_boosterPidToInvokerPid[arg1] = arg2;
|
|
|
|
|
}
|
|
|
|
|
else if (token == "booster-invoker-fd")
|
|
|
|
|
{
|
|
|
|
|
int arg1, arg2;
|
|
|
|
|
ss >> arg1;
|
|
|
|
|
ss >> arg2;
|
|
|
|
|
Logger::logDebug("Daemon: restored m_boosterPidToInvokerFd[%d] = %d", arg1, arg2);
|
|
|
|
|
m_boosterPidToInvokerFd[arg1] = arg2;
|
|
|
|
|
}
|
|
|
|
|
else if (token == "booster-pid")
|
|
|
|
|
{
|
|
|
|
|
int arg1;
|
|
|
|
|
ss >> arg1;
|
|
|
|
|
Logger::logDebug("Daemon: restored m_boosterPid = %d", arg1);
|
|
|
|
|
|
|
|
|
|
m_boosterPid = arg1;
|
|
|
|
|
}
|
|
|
|
|
else if (token == "launcher-socket")
|
|
|
|
|
{
|
|
|
|
|
int arg1, arg2;
|
|
|
|
|
ss >> arg1;
|
|
|
|
|
ss >> arg2;
|
|
|
|
|
Logger::logDebug("Daemon: restored m_boosterLauncherSocket[] = {%d, %d}", arg1, arg2);
|
|
|
|
|
m_boosterLauncherSocket[0] = arg1;
|
|
|
|
|
m_boosterLauncherSocket[1] = arg2;
|
|
|
|
|
}
|
|
|
|
|
else if (token == "sigpipe-fd")
|
|
|
|
|
{
|
|
|
|
|
int arg1, arg2;
|
|
|
|
|
ss >> arg1;
|
|
|
|
|
ss >> arg2;
|
|
|
|
|
Logger::logDebug("Daemon: restored m_sigPipeFd[] = {%d, %d}", arg1, arg2);
|
|
|
|
|
m_sigPipeFd[0] = arg1;
|
|
|
|
|
m_sigPipeFd[1] = arg2;
|
|
|
|
|
}
|
|
|
|
|
else if (token == "socket-hash")
|
|
|
|
|
{
|
|
|
|
|
std::string arg1;
|
|
|
|
|
int arg2;
|
|
|
|
|
ss >> arg1;
|
|
|
|
|
ss >> arg2;
|
|
|
|
|
m_socketManager->addMapping(arg1, arg2);
|
|
|
|
|
Logger::logDebug("Daemon: restored socketHash[%s] = %d", arg1.c_str(), arg2);
|
|
|
|
|
}
|
|
|
|
|
else if (token == "debug-mode")
|
|
|
|
|
{
|
|
|
|
|
bool arg1;
|
|
|
|
|
ss >> arg1;
|
|
|
|
|
m_debugMode = arg1;
|
|
|
|
|
Logger::setDebugMode(m_debugMode);
|
|
|
|
|
Logger::logDebug("Daemon: restored m_debugMode = %d", arg1);
|
|
|
|
|
}
|
|
|
|
|
else if (token == "boot-mode")
|
|
|
|
|
{
|
|
|
|
|
bool arg1;
|
|
|
|
|
ss >> arg1;
|
|
|
|
|
m_bootMode = arg1;
|
|
|
|
|
Logger::logDebug("Daemon: restored m_bootMode = %d", arg1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (std::ifstream::failure e)
|
|
|
|
|
{
|
|
|
|
|
// Ran out of saved state before "end" token
|
|
|
|
|
// or there was some other error in restoring the sate.
|
|
|
|
|
Logger::logError("Daemon: Failed to restore saved state, exiting.");
|
|
|
|
|
}
|
|
|
|
|
catch (char *err)
|
|
|
|
|
{
|
|
|
|
|
// Some other error, e.g. stale state file
|
|
|
|
|
Logger::logError(err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// In debug mode it is better to leave the file there
|
|
|
|
|
// so it can be examined.
|
|
|
|
|
if (!m_debugMode && remove(m_stateFile.c_str()) == -1)
|
|
|
|
|
{
|
|
|
|
|
Logger::logError("Daemon: could not remove state file %s", m_stateFile.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This is only reached if state restore was unsuccessful.
|
|
|
|
|
_exit(1);
|
|
|
|
|
}
|
|
|
|
|
|