2015-12-19 16:20:04 -06:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
|
|
|
/*
|
|
|
|
* This file is part of the LibreOffice project.
|
|
|
|
*
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
|
|
|
#include <utime.h>
|
|
|
|
#include <ftw.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <dlfcn.h>
|
|
|
|
|
2016-01-06 09:08:54 -06:00
|
|
|
#include <atomic>
|
2015-12-19 16:20:04 -06:00
|
|
|
#include <mutex>
|
|
|
|
#include <cstring>
|
|
|
|
#include <cassert>
|
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
|
|
|
#include <deque>
|
|
|
|
|
|
|
|
#include <Poco/Types.h>
|
|
|
|
#include <Poco/Random.h>
|
|
|
|
#include <Poco/Path.h>
|
|
|
|
#include <Poco/File.h>
|
|
|
|
#include <Poco/ThreadLocal.h>
|
|
|
|
#include <Poco/Process.h>
|
|
|
|
#include <Poco/Thread.h>
|
|
|
|
#include <Poco/NamedMutex.h>
|
|
|
|
|
2015-12-27 16:23:43 -06:00
|
|
|
#include "Common.hpp"
|
2015-12-29 19:34:53 -06:00
|
|
|
#include "Capabilities.hpp"
|
2015-12-19 16:20:04 -06:00
|
|
|
#include "Util.hpp"
|
|
|
|
|
|
|
|
// First include the grist of the helper process - ideally
|
|
|
|
// we can avoid execve and share lots of memory here. We
|
|
|
|
// can't link to a non-PIC translation unit though, so
|
|
|
|
// include to share.
|
|
|
|
#define LOOLKIT_NO_MAIN 1
|
|
|
|
#include "LOOLKit.cpp"
|
|
|
|
|
|
|
|
#define LIB_SOFFICEAPP "lib" "sofficeapp" ".so"
|
2016-01-06 03:36:52 -06:00
|
|
|
#define LIB_MERGED "lib" "mergedlo" ".so"
|
2015-12-19 16:20:04 -06:00
|
|
|
#define LIB_SCLO "lib" "sclo" ".so"
|
|
|
|
#define LIB_SWLO "lib" "swlo" ".so"
|
|
|
|
#define LIB_SDLO "lib" "sdlo" ".so"
|
2015-12-28 16:23:05 -06:00
|
|
|
#define JAILED_LOOLKIT_PATH "/usr/bin/loolkit"
|
2015-12-19 16:20:04 -06:00
|
|
|
|
|
|
|
typedef int (LokHookPreInit) ( const char *install_path, const char *user_profile_path );
|
|
|
|
|
|
|
|
using Poco::Path;
|
|
|
|
using Poco::File;
|
|
|
|
using Poco::ThreadLocal;
|
|
|
|
using Poco::Process;
|
|
|
|
using Poco::Thread;
|
|
|
|
using Poco::ProcessHandle;
|
|
|
|
|
|
|
|
const std::string FIFO_FILE = "/tmp/loolwsdfifo";
|
|
|
|
const std::string FIFO_BROKER = "/tmp/loolbroker.fifo";
|
|
|
|
const std::string BROKER_SUFIX = ".fifo";
|
|
|
|
const std::string BROKER_PREFIX = "/tmp/lokit";
|
|
|
|
|
|
|
|
static int readerChild = -1;
|
|
|
|
static int readerBroker = -1;
|
|
|
|
|
2016-01-06 09:08:54 -06:00
|
|
|
static std::atomic<unsigned> forkCounter;
|
2016-01-08 17:02:09 -06:00
|
|
|
static std::atomic<std::chrono::seconds> maintenance;
|
2015-12-19 16:20:04 -06:00
|
|
|
static unsigned int childCounter = 0;
|
2016-01-05 06:51:05 -06:00
|
|
|
static unsigned int numPreSpawnedChildren = 0;
|
2015-12-19 16:20:04 -06:00
|
|
|
|
|
|
|
static std::mutex forkMutex;
|
|
|
|
static std::map<Process::PID, int> _childProcesses;
|
|
|
|
static std::map<std::string, Process::PID> _cacheURL;
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
ThreadLocal<std::string> sourceForLinkOrCopy;
|
|
|
|
ThreadLocal<Path> destinationForLinkOrCopy;
|
|
|
|
|
|
|
|
int linkOrCopyFunction(const char *fpath,
|
|
|
|
const struct stat* /*sb*/,
|
|
|
|
int typeflag,
|
|
|
|
struct FTW* /*ftwbuf*/)
|
|
|
|
{
|
|
|
|
if (strcmp(fpath, sourceForLinkOrCopy->c_str()) == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
assert(fpath[strlen(sourceForLinkOrCopy->c_str())] == '/');
|
|
|
|
const char *relativeOldPath = fpath + strlen(sourceForLinkOrCopy->c_str()) + 1;
|
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
if (strcmp(relativeOldPath, "PkgInfo") == 0)
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
Path newPath(*destinationForLinkOrCopy, Path(relativeOldPath));
|
|
|
|
|
|
|
|
switch (typeflag)
|
|
|
|
{
|
|
|
|
case FTW_F:
|
|
|
|
File(newPath.parent()).createDirectories();
|
|
|
|
if (link(fpath, newPath.toString().c_str()) == -1)
|
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Error: link(\"" + std::string(fpath) + "\",\"" + newPath.toString() +
|
|
|
|
"\") failed. Exiting.");
|
2015-12-19 16:20:04 -06:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FTW_DP:
|
|
|
|
{
|
|
|
|
struct stat st;
|
|
|
|
if (stat(fpath, &st) == -1)
|
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Error: stat(\"" + std::string(fpath) + "\") failed.");
|
2015-12-19 16:20:04 -06:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
File(newPath).createDirectories();
|
|
|
|
struct utimbuf ut;
|
|
|
|
ut.actime = st.st_atime;
|
|
|
|
ut.modtime = st.st_mtime;
|
|
|
|
if (utime(newPath.toString().c_str(), &ut) == -1)
|
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Error: utime(\"" + newPath.toString() + "\", &ut) failed.");
|
2015-12-19 16:20:04 -06:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FTW_DNR:
|
2015-12-25 12:50:53 -06:00
|
|
|
Log::error("Cannot read directory '" + std::string(fpath) + "'");
|
2015-12-19 16:20:04 -06:00
|
|
|
return 1;
|
|
|
|
case FTW_NS:
|
2015-12-25 12:50:53 -06:00
|
|
|
Log::error("nftw: stat failed for '" + std::string(fpath) + "'");
|
2015-12-19 16:20:04 -06:00
|
|
|
return 1;
|
|
|
|
case FTW_SLN:
|
2015-12-25 12:50:53 -06:00
|
|
|
Log::error("nftw: symlink to nonexistent file: '" + std::string(fpath) + "', ignored.");
|
2015-12-19 16:20:04 -06:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void linkOrCopy(const std::string& source, const Path& destination)
|
|
|
|
{
|
|
|
|
*sourceForLinkOrCopy = source;
|
|
|
|
if (sourceForLinkOrCopy->back() == '/')
|
|
|
|
sourceForLinkOrCopy->pop_back();
|
|
|
|
*destinationForLinkOrCopy = destination;
|
|
|
|
if (nftw(source.c_str(), linkOrCopyFunction, 10, FTW_DEPTH) == -1)
|
2015-12-25 12:50:53 -06:00
|
|
|
Log::error("linkOrCopy: nftw() failed for '" + source + "'");
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
2016-01-09 10:26:04 -06:00
|
|
|
|
|
|
|
void requestAbnormalTermination(const Process::PID aPID)
|
|
|
|
{
|
|
|
|
if (kill(aPID, SIGTERM) != 0)
|
|
|
|
{
|
|
|
|
Log::info("Cannot terminate lokit [" + std::to_string(aPID) + "]");
|
|
|
|
}
|
|
|
|
}
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
class PipeRunnable: public Runnable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
PipeRunnable()
|
2016-01-03 12:25:55 -06:00
|
|
|
: _pStart(nullptr),
|
|
|
|
_pEnd(nullptr)
|
2015-12-19 16:20:04 -06:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t getResponseLine(int nPipeReader, std::string& aLine)
|
|
|
|
{
|
|
|
|
ssize_t nBytes = -1;
|
|
|
|
aLine.clear();
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
if ( _pStart == _pEnd )
|
|
|
|
{
|
|
|
|
nBytes = Util::readMessage(nPipeReader, _aBuffer, sizeof(_aBuffer));
|
|
|
|
if ( nBytes < 0 )
|
|
|
|
{
|
2015-12-24 21:24:26 -06:00
|
|
|
_pStart = _pEnd = nullptr;
|
2015-12-19 16:20:04 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
_pStart = _aBuffer;
|
|
|
|
_pEnd = _aBuffer + nBytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( _pStart != _pEnd )
|
|
|
|
{
|
|
|
|
char aChar = *_pStart++;
|
|
|
|
while (_pStart != _pEnd && aChar != '\r' && aChar != '\n')
|
|
|
|
{
|
|
|
|
aLine += aChar;
|
|
|
|
aChar = *_pStart++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( aChar == '\r' && *_pStart == '\n')
|
|
|
|
{
|
|
|
|
_pStart++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nBytes;
|
|
|
|
}
|
|
|
|
|
2016-01-07 12:55:11 -06:00
|
|
|
bool isOKResponse(int nPID)
|
|
|
|
{
|
|
|
|
std::string aResponse;
|
|
|
|
|
|
|
|
if (getResponseLine(readerChild, aResponse) < 0)
|
|
|
|
{
|
|
|
|
Log::error("Error reading child response: " + std::to_string(nPID) + ". Clearing cache.");
|
2016-01-09 10:26:04 -06:00
|
|
|
requestAbnormalTermination(nPID);
|
2016-01-07 12:55:11 -06:00
|
|
|
_cacheURL.clear();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringTokenizer tokens(aResponse, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
|
|
|
|
return (tokens[1] == "ok" ? true : false);
|
|
|
|
}
|
|
|
|
|
2015-12-19 16:20:04 -06:00
|
|
|
ssize_t sendMessage(int nPipeWriter, const std::string& aMessage)
|
|
|
|
{
|
|
|
|
ssize_t nBytes = -1;
|
|
|
|
|
|
|
|
nBytes = Util::writeFIFO(nPipeWriter, aMessage.c_str(), aMessage.length());
|
|
|
|
if ( nBytes < 0 )
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Error writting to child pipe.");
|
2015-12-19 16:20:04 -06:00
|
|
|
|
|
|
|
return nBytes;
|
|
|
|
}
|
|
|
|
|
2016-01-03 12:25:55 -06:00
|
|
|
ssize_t createThread(Process::PID nPID, const std::string& aTID, const std::string& aURL)
|
2015-12-19 16:20:04 -06:00
|
|
|
{
|
2016-01-03 12:25:55 -06:00
|
|
|
std::string aMessage = "thread " + aTID + " " + aURL + "\r\n";
|
2015-12-19 16:20:04 -06:00
|
|
|
return sendMessage(_childProcesses[nPID], aMessage);
|
|
|
|
}
|
|
|
|
|
2016-01-08 17:02:09 -06:00
|
|
|
void verifyChilds()
|
|
|
|
{
|
|
|
|
std::string aMessage;
|
|
|
|
bool bError = false;
|
|
|
|
|
|
|
|
// sanity cache
|
|
|
|
for (auto it =_cacheURL.cbegin(); it != _cacheURL.cend(); )
|
|
|
|
{
|
|
|
|
aMessage = "search " + it->first + "\r\n";
|
|
|
|
if (sendMessage(_childProcesses[it->second], aMessage) < 0)
|
|
|
|
{
|
|
|
|
bError = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isOKResponse(it->second))
|
|
|
|
{
|
|
|
|
Log::debug() << "Removed expired Kit [" + std::to_string(it->second) + "] hosts URL [" + it->first + "] -> " << Log::end;
|
|
|
|
_cacheURL.erase(it++);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
it++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bError)
|
|
|
|
_cacheURL.clear();
|
|
|
|
}
|
|
|
|
|
2015-12-19 16:20:04 -06:00
|
|
|
Process::PID searchURL(const std::string& aURL)
|
|
|
|
{
|
2016-01-04 18:51:03 -06:00
|
|
|
const std::string aMessage = "search " + aURL + "\r\n";
|
2015-12-19 16:20:04 -06:00
|
|
|
|
2016-01-04 18:51:03 -06:00
|
|
|
Process::PID nPID = -1;
|
|
|
|
for (auto& it : _childProcesses)
|
2015-12-19 16:20:04 -06:00
|
|
|
{
|
2016-01-04 18:51:03 -06:00
|
|
|
assert(it.first > 0 && it.second > 0);
|
2015-12-19 16:20:04 -06:00
|
|
|
|
2016-01-04 18:51:03 -06:00
|
|
|
Log::trace("Query to kit [" + std::to_string(it.first) + "]: " + aMessage);
|
|
|
|
ssize_t nBytes = Util::writeFIFO(it.second, aMessage.c_str(), aMessage.length());
|
2015-12-19 16:20:04 -06:00
|
|
|
if ( nBytes < 0 )
|
|
|
|
{
|
2016-01-04 18:51:03 -06:00
|
|
|
Log::error("Error writting to child pipe: " + std::to_string(it.first) + ". Clearing cache.");
|
2016-01-09 10:26:04 -06:00
|
|
|
requestAbnormalTermination(it.first);
|
2016-01-04 18:51:03 -06:00
|
|
|
_cacheURL.clear();
|
2015-12-19 16:20:04 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-01-04 18:51:03 -06:00
|
|
|
std::string aResponse;
|
2015-12-19 16:20:04 -06:00
|
|
|
nBytes = getResponseLine(readerChild, aResponse);
|
2016-01-04 18:51:03 -06:00
|
|
|
Log::trace("Response from kit [" + std::to_string(it.first) + "]: " + aResponse);
|
2015-12-19 16:20:04 -06:00
|
|
|
if ( nBytes < 0 )
|
|
|
|
{
|
2016-01-04 18:51:03 -06:00
|
|
|
Log::error("Error reading child response: " + std::to_string(it.first) + ". Clearing cache.");
|
2016-01-09 10:26:04 -06:00
|
|
|
requestAbnormalTermination(it.first);
|
2016-01-04 18:51:03 -06:00
|
|
|
_cacheURL.clear();
|
2015-12-19 16:20:04 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringTokenizer tokens(aResponse, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
|
|
|
|
if (tokens[1] == "ok")
|
|
|
|
{
|
2016-01-04 18:51:03 -06:00
|
|
|
// Found, but find all empty instances.
|
|
|
|
nPID = it.first;
|
|
|
|
Log::debug("Kit [" + std::to_string(nPID) + "] hosts URL [" + aURL + "].");
|
|
|
|
break;
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
else if (tokens[1] == "empty")
|
|
|
|
{
|
2016-01-04 18:51:03 -06:00
|
|
|
// Remember the last empty.
|
|
|
|
nPID = it.first;
|
|
|
|
Log::debug("Kit [" + std::to_string(nPID) + "] is empty.");
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-04 18:51:03 -06:00
|
|
|
return nPID;
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void handleInput(const std::string& aMessage)
|
|
|
|
{
|
|
|
|
StringTokenizer tokens(aMessage, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
|
|
|
|
if (tokens[0] == "request" && tokens.count() == 3)
|
|
|
|
{
|
2015-12-25 11:35:23 -06:00
|
|
|
const std::string aTID = tokens[1];
|
|
|
|
const std::string aURL = tokens[2];
|
|
|
|
|
2016-01-04 18:51:03 -06:00
|
|
|
Log::debug("Finding kit for URL [" + aURL + "] on thread [" + aTID + "].");
|
2015-12-19 16:20:04 -06:00
|
|
|
|
|
|
|
// check cache
|
2015-12-24 21:24:26 -06:00
|
|
|
const auto aIterURL = _cacheURL.find(aURL);
|
2015-12-19 16:20:04 -06:00
|
|
|
if ( aIterURL != _cacheURL.end() )
|
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::debug("Cache found URL [" + aURL + "] hosted on child [" + std::to_string(aIterURL->second) +
|
|
|
|
"]. Creating view for thread [" + aTID + "].");
|
2016-01-03 12:25:55 -06:00
|
|
|
if (createThread(aIterURL->second, aTID, aURL) < 0)
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Cache: Error creating thread.");
|
2015-12-19 16:20:04 -06:00
|
|
|
|
2016-01-07 12:55:11 -06:00
|
|
|
if (!isOKResponse(aIterURL->second))
|
|
|
|
Log::error("Cache Failed: Creating view for thread [" + aTID + "].");
|
|
|
|
|
2015-12-19 16:20:04 -06:00
|
|
|
return;
|
|
|
|
}
|
2016-01-04 18:51:03 -06:00
|
|
|
else
|
|
|
|
{
|
|
|
|
Log::debug("URL [" + aURL + "] is not in cache, searching " +
|
|
|
|
std::to_string(_childProcesses.size()) + " kits.");
|
|
|
|
}
|
2015-12-19 16:20:04 -06:00
|
|
|
|
|
|
|
// not found in cache, full search.
|
2016-01-04 18:51:03 -06:00
|
|
|
const Process::PID nPID = searchURL(aURL);
|
2015-12-19 16:20:04 -06:00
|
|
|
if ( nPID > 0 )
|
|
|
|
{
|
2016-01-04 18:51:03 -06:00
|
|
|
Log::debug("Creating view for URL [" + aURL + "] for thread [" +
|
|
|
|
aTID + "] on kit [" + std::to_string(nPID) + "].");
|
2016-01-03 12:25:55 -06:00
|
|
|
if (createThread(nPID, aTID, aURL) < 0)
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Search: Error creating thread.");
|
2016-01-07 12:55:11 -06:00
|
|
|
else if (isOKResponse(nPID))
|
2015-12-19 16:20:04 -06:00
|
|
|
_cacheURL[aURL] = nPID;
|
2016-01-07 12:55:11 -06:00
|
|
|
else
|
|
|
|
Log::error("Failed: Creating view for thread [" + aTID + "].");
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
2016-01-04 18:51:03 -06:00
|
|
|
else
|
2015-12-19 16:20:04 -06:00
|
|
|
{
|
2016-01-05 06:51:05 -06:00
|
|
|
Log::info("No children available, creating [" + std::to_string(numPreSpawnedChildren) + "] childs");
|
|
|
|
forkCounter = numPreSpawnedChildren;
|
2016-01-04 18:51:03 -06:00
|
|
|
}
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void run() override
|
|
|
|
{
|
|
|
|
std::string aMessage;
|
2015-12-30 19:01:07 -06:00
|
|
|
char aBuffer[PIPE_BUFFER];
|
2015-12-19 16:20:04 -06:00
|
|
|
char* pStart;
|
|
|
|
char* pEnd;
|
|
|
|
|
|
|
|
struct pollfd aPoll;
|
|
|
|
ssize_t nBytes = -1;
|
|
|
|
|
|
|
|
aPoll.fd = readerBroker;
|
|
|
|
aPoll.events = POLLIN;
|
|
|
|
aPoll.revents = 0;
|
|
|
|
|
2015-12-28 16:24:59 -06:00
|
|
|
pStart = aBuffer;
|
|
|
|
pEnd = aBuffer;
|
2015-12-19 16:20:04 -06:00
|
|
|
|
2016-01-03 12:25:55 -06:00
|
|
|
static const std::string thread_name = "brk_pipe_reader";
|
2015-12-19 16:20:04 -06:00
|
|
|
#ifdef __linux
|
2015-12-26 10:33:01 -06:00
|
|
|
if (prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(thread_name.c_str()), 0, 0, 0) != 0)
|
|
|
|
Log::error("Cannot set thread name to " + thread_name + ".");
|
2015-12-19 16:20:04 -06:00
|
|
|
#endif
|
2015-12-26 10:33:01 -06:00
|
|
|
Log::debug("Thread [" + thread_name + "] started.");
|
2015-12-19 16:20:04 -06:00
|
|
|
|
2015-12-29 18:59:17 -06:00
|
|
|
while (!TerminationFlag)
|
2015-12-19 16:20:04 -06:00
|
|
|
{
|
|
|
|
if ( pStart == pEnd )
|
|
|
|
{
|
2015-12-26 10:27:44 -06:00
|
|
|
if (poll(&aPoll, 1, -1) < 0)
|
|
|
|
{
|
|
|
|
Log::error("Failed to poll pipe [" + FIFO_FILE + "].");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (aPoll.revents & POLLIN)
|
2015-12-19 16:20:04 -06:00
|
|
|
{
|
2015-12-28 16:24:59 -06:00
|
|
|
nBytes = Util::readFIFO(readerBroker, aBuffer, sizeof(aBuffer));
|
2015-12-19 16:20:04 -06:00
|
|
|
if (nBytes < 0)
|
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
pStart = pEnd = nullptr;
|
2015-12-26 10:27:44 -06:00
|
|
|
Log::error("Error reading message from pipe [" + FIFO_FILE + "].");
|
2015-12-19 16:20:04 -06:00
|
|
|
continue;
|
|
|
|
}
|
2015-12-28 16:24:59 -06:00
|
|
|
pStart = aBuffer;
|
|
|
|
pEnd = aBuffer + nBytes;
|
2015-12-26 10:27:44 -06:00
|
|
|
}
|
|
|
|
else
|
|
|
|
if (aPoll.revents & (POLLERR | POLLHUP))
|
|
|
|
{
|
2015-12-30 10:41:41 -06:00
|
|
|
Log::error("Broken pipe [" + FIFO_FILE + "] with wsd.");
|
2015-12-26 10:27:44 -06:00
|
|
|
break;
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pStart != pEnd )
|
|
|
|
{
|
|
|
|
char aChar = *pStart++;
|
|
|
|
while (pStart != pEnd && aChar != '\r' && aChar != '\n')
|
|
|
|
{
|
|
|
|
aMessage += aChar;
|
|
|
|
aChar = *pStart++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( aChar == '\r' && *pStart == '\n')
|
|
|
|
{
|
|
|
|
pStart++;
|
|
|
|
|
|
|
|
forkMutex.lock();
|
2016-01-08 17:02:09 -06:00
|
|
|
if (maintenance.load() > std::chrono::seconds(10))
|
|
|
|
{
|
|
|
|
maintenance = std::chrono::seconds::zero();
|
|
|
|
verifyChilds();
|
|
|
|
}
|
2015-12-19 16:20:04 -06:00
|
|
|
handleInput(aMessage);
|
|
|
|
aMessage.clear();
|
|
|
|
forkMutex.unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-12-26 10:33:01 -06:00
|
|
|
|
|
|
|
Log::debug("Thread [" + thread_name + "] finished.");
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
char* _pStart;
|
|
|
|
char* _pEnd;
|
2015-12-30 19:01:07 -06:00
|
|
|
char _aBuffer[PIPE_BUFFER];
|
2015-12-19 16:20:04 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
/// Initializes LibreOfficeKit for cross-fork re-use.
|
|
|
|
static bool globalPreinit(const std::string &loSubPath)
|
|
|
|
{
|
|
|
|
void *handle;
|
|
|
|
LokHookPreInit* preInit;
|
|
|
|
|
|
|
|
std::string fname = "/" + loSubPath + "/program/" LIB_SOFFICEAPP;
|
|
|
|
handle = dlopen(fname.c_str(), RTLD_GLOBAL|RTLD_NOW);
|
|
|
|
if (!handle)
|
|
|
|
{
|
2016-01-06 03:36:52 -06:00
|
|
|
Log::warn("Failed to load " + std::string(LIB_SOFFICEAPP) + " library. Trying " + std::string(LIB_MERGED));
|
|
|
|
fname = "/" + loSubPath + "/program/" LIB_MERGED;
|
|
|
|
handle = dlopen(fname.c_str(), RTLD_GLOBAL|RTLD_NOW);
|
|
|
|
if (!handle)
|
|
|
|
{
|
|
|
|
Log::warn("Failed to load " + std::string(LIB_MERGED) + " library.");
|
|
|
|
return false;
|
|
|
|
}
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
preInit = (LokHookPreInit *)dlsym(handle, "lok_preinit");
|
|
|
|
if (!preInit)
|
|
|
|
{
|
2016-01-08 20:53:57 -06:00
|
|
|
Log::warn("Note: No lok_preinit hook in " + std::string(LIB_SOFFICEAPP) +
|
|
|
|
" library. Cannot fork, will execv instead.");
|
2015-12-19 16:20:04 -06:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return preInit(("/" + loSubPath + "/program").c_str(), "file:///user") == 0;
|
|
|
|
}
|
|
|
|
|
2015-12-27 16:58:52 -06:00
|
|
|
static int createLibreOfficeKit(const bool sharePages, const std::string& loSubPath,
|
2016-01-06 21:47:01 -06:00
|
|
|
const std::string& jailId)
|
2015-12-19 16:20:04 -06:00
|
|
|
{
|
|
|
|
Poco::UInt64 child;
|
|
|
|
int nFIFOWriter = -1;
|
|
|
|
|
2016-01-04 15:53:11 -06:00
|
|
|
const std::string pipe = BROKER_PREFIX + std::to_string(childCounter++) + BROKER_SUFIX;
|
|
|
|
|
|
|
|
if (mkfifo(pipe.c_str(), 0666) < 0)
|
|
|
|
{
|
|
|
|
Log::error("Error: mkfifo failed.");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-12-19 16:20:04 -06:00
|
|
|
if (sharePages)
|
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::debug("Forking LibreOfficeKit.");
|
2015-12-19 16:20:04 -06:00
|
|
|
|
2015-12-24 21:19:50 -06:00
|
|
|
Poco::UInt64 pid;
|
2015-12-19 16:20:04 -06:00
|
|
|
if (!(pid = fork()))
|
2015-12-24 21:24:26 -06:00
|
|
|
{
|
|
|
|
// child
|
2016-01-06 21:47:01 -06:00
|
|
|
lokit_main(loSubPath, jailId, pipe);
|
2015-12-19 16:20:04 -06:00
|
|
|
_exit(0);
|
|
|
|
}
|
|
|
|
else
|
2015-12-24 21:24:26 -06:00
|
|
|
{
|
|
|
|
// parent
|
2015-12-19 16:20:04 -06:00
|
|
|
child = pid; // (somehow - switch the hash to use real pids or ?) ...
|
2016-01-04 15:53:11 -06:00
|
|
|
Log::info("Forked kit [" + std::to_string(child) + "].");
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-12-27 16:46:42 -06:00
|
|
|
Process::Args args;
|
2015-12-19 16:20:04 -06:00
|
|
|
args.push_back("--losubpath=" + loSubPath);
|
2016-01-06 21:47:01 -06:00
|
|
|
args.push_back("--jailid=" + jailId);
|
2015-12-19 16:20:04 -06:00
|
|
|
args.push_back("--pipe=" + pipe);
|
2015-12-28 16:23:05 -06:00
|
|
|
args.push_back("--clientport=" + std::to_string(ClientPortNumber));
|
2015-12-19 16:20:04 -06:00
|
|
|
|
2015-12-28 16:23:05 -06:00
|
|
|
Log::info("Launching LibreOfficeKit #" + std::to_string(childCounter) +
|
|
|
|
": " + JAILED_LOOLKIT_PATH + " " +
|
2015-12-24 21:19:50 -06:00
|
|
|
Poco::cat(std::string(" "), args.begin(), args.end()));
|
2015-12-19 16:20:04 -06:00
|
|
|
|
2015-12-28 16:23:05 -06:00
|
|
|
ProcessHandle procChild = Process::launch(JAILED_LOOLKIT_PATH, args);
|
2015-12-19 16:20:04 -06:00
|
|
|
child = procChild.id();
|
2016-01-04 15:53:11 -06:00
|
|
|
Log::info("Spawned kit [" + std::to_string(child) + "].");
|
|
|
|
|
2015-12-28 16:23:05 -06:00
|
|
|
if (!Process::isRunning(procChild))
|
|
|
|
{
|
|
|
|
// This can happen if we fail to copy it, or bad chroot etc.
|
2016-01-04 15:53:11 -06:00
|
|
|
Log::error("Error: loolkit [" + std::to_string(child) + "] was stillborn.");
|
2015-12-28 16:23:05 -06:00
|
|
|
return -1;
|
|
|
|
}
|
2016-01-04 15:53:11 -06:00
|
|
|
}
|
2015-12-19 16:20:04 -06:00
|
|
|
|
2016-01-04 15:53:11 -06:00
|
|
|
if ( (nFIFOWriter = open(pipe.c_str(), O_WRONLY)) < 0 )
|
|
|
|
{
|
|
|
|
Log::error("Error: failed to open write pipe [" + pipe + "] with kit. Abandoning child.");
|
2016-01-09 10:26:04 -06:00
|
|
|
requestAbnormalTermination(child);
|
2016-01-04 15:53:11 -06:00
|
|
|
return -1;
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
|
2015-12-28 16:23:05 -06:00
|
|
|
Log::info() << "Adding Kit #" << childCounter << " PID " << child << Log::end;
|
2015-12-19 16:20:04 -06:00
|
|
|
_childProcesses[child] = nFIFOWriter;
|
|
|
|
return child;
|
|
|
|
}
|
|
|
|
|
2015-12-27 16:58:52 -06:00
|
|
|
static int startupLibreOfficeKit(const bool sharePages, const int nLOKits,
|
2016-01-06 21:47:01 -06:00
|
|
|
const std::string& loSubPath, const std::string& jailId)
|
2015-12-19 16:20:04 -06:00
|
|
|
{
|
|
|
|
Process::PID pId = -1;
|
|
|
|
|
2015-12-27 16:58:52 -06:00
|
|
|
Log::info() << "Starting " << nLOKits << " LoKit instaces." << Log::end;
|
2015-12-19 16:20:04 -06:00
|
|
|
for (int nCntr = nLOKits; nCntr; nCntr--)
|
|
|
|
{
|
2016-01-06 21:47:01 -06:00
|
|
|
if ((pId = createLibreOfficeKit(sharePages, loSubPath, jailId)) < 0)
|
2015-12-19 16:20:04 -06:00
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Error: failed to create LibreOfficeKit.");
|
2015-12-19 16:20:04 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-20 11:59:26 -06:00
|
|
|
return pId;
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
|
2016-01-08 21:34:34 -06:00
|
|
|
|
|
|
|
static bool waitForTerminationChild(const Process::PID aPID)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
short nCntr = 3;
|
|
|
|
|
|
|
|
while (nCntr-- > 0)
|
|
|
|
{
|
|
|
|
waitpid(aPID, &status, WUNTRACED | WNOHANG);
|
|
|
|
if (WIFEXITED(status))
|
|
|
|
break;
|
|
|
|
|
|
|
|
sleep(MAINTENANCE_INTERVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return nCntr;
|
|
|
|
}
|
|
|
|
|
2015-12-19 16:20:04 -06:00
|
|
|
// Broker process
|
|
|
|
int main(int argc, char** argv)
|
|
|
|
{
|
2015-12-24 21:24:26 -06:00
|
|
|
if (std::getenv("SLEEPFORDEBUGGER"))
|
|
|
|
{
|
|
|
|
std::cerr << "Sleeping " << std::getenv("SLEEPFORDEBUGGER")
|
|
|
|
<< " seconds to attach debugger to process "
|
|
|
|
<< Process::id() << std::endl;
|
|
|
|
Thread::sleep(std::stoul(std::getenv("SLEEPFORDEBUGGER")) * 1000);
|
|
|
|
}
|
|
|
|
|
2015-12-19 16:20:04 -06:00
|
|
|
// Initialization
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::initialize("brk");
|
|
|
|
|
2016-01-09 12:51:55 -06:00
|
|
|
Util::setSignals(false);
|
2015-12-28 17:24:29 -06:00
|
|
|
|
2015-12-19 16:20:04 -06:00
|
|
|
std::string childRoot;
|
2016-01-06 21:47:01 -06:00
|
|
|
std::string jailId;
|
2015-12-19 16:20:04 -06:00
|
|
|
std::string loSubPath;
|
|
|
|
std::string sysTemplate;
|
|
|
|
std::string loTemplate;
|
|
|
|
|
|
|
|
for (int i = 0; i < argc; ++i)
|
|
|
|
{
|
|
|
|
char *cmd = argv[i];
|
2015-12-24 21:24:26 -06:00
|
|
|
char *eq = nullptr;
|
2015-12-19 16:20:04 -06:00
|
|
|
if (strstr(cmd, "--losubpath=") == cmd)
|
|
|
|
{
|
|
|
|
eq = strchrnul(cmd, '=');
|
|
|
|
if (*eq)
|
|
|
|
loSubPath = std::string(++eq);
|
|
|
|
}
|
|
|
|
else if (strstr(cmd, "--systemplate=") == cmd)
|
|
|
|
{
|
|
|
|
eq = strchrnul(cmd, '=');
|
|
|
|
if (*eq)
|
|
|
|
sysTemplate = std::string(++eq);
|
|
|
|
}
|
|
|
|
else if (strstr(cmd, "--lotemplate=") == cmd)
|
|
|
|
{
|
|
|
|
eq = strchrnul(cmd, '=');
|
|
|
|
if (*eq)
|
|
|
|
loTemplate = std::string(++eq);
|
|
|
|
}
|
|
|
|
else if (strstr(cmd, "--childroot=") == cmd)
|
|
|
|
{
|
|
|
|
eq = strchrnul(cmd, '=');
|
|
|
|
if (*eq)
|
|
|
|
childRoot = std::string(++eq);
|
|
|
|
}
|
2016-01-06 21:47:01 -06:00
|
|
|
else if (strstr(cmd, "--jailid=") == cmd)
|
|
|
|
{
|
|
|
|
eq = strchrnul(cmd, '=');
|
|
|
|
if (*eq)
|
|
|
|
jailId = std::string(++eq);
|
|
|
|
}
|
2015-12-19 16:20:04 -06:00
|
|
|
else if (strstr(cmd, "--numprespawns=") == cmd)
|
|
|
|
{
|
|
|
|
eq = strchrnul(cmd, '=');
|
|
|
|
if (*eq)
|
2015-12-27 16:58:52 -06:00
|
|
|
numPreSpawnedChildren = std::stoi(std::string(++eq));
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
2015-12-27 16:46:42 -06:00
|
|
|
else if (strstr(cmd, "--clientport=") == cmd)
|
|
|
|
{
|
|
|
|
eq = strchrnul(cmd, '=');
|
|
|
|
if (*eq)
|
|
|
|
ClientPortNumber = std::stoll(std::string(++eq));
|
|
|
|
}
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if (loSubPath.empty())
|
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Error: --losubpath is empty");
|
2015-12-19 16:20:04 -06:00
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sysTemplate.empty())
|
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Error: --losubpath is empty");
|
2015-12-19 16:20:04 -06:00
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (loTemplate.empty())
|
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Error: --lotemplate is empty");
|
2015-12-19 16:20:04 -06:00
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (childRoot.empty())
|
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Error: --childroot is empty");
|
2015-12-19 16:20:04 -06:00
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
2015-12-27 16:58:52 -06:00
|
|
|
if ( !numPreSpawnedChildren )
|
2015-12-19 16:20:04 -06:00
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Error: --numprespawns is 0");
|
2015-12-19 16:20:04 -06:00
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( (readerBroker = open(FIFO_FILE.c_str(), O_RDONLY) ) < 0 )
|
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Error: failed to open pipe [" + FIFO_FILE + "] read only. Exiting.");
|
2015-12-19 16:20:04 -06:00
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
Poco::Environment::get("LD_BIND_NOW");
|
|
|
|
}
|
2015-12-25 12:50:53 -06:00
|
|
|
catch (const Poco::NotFoundException& exc)
|
2015-12-19 16:20:04 -06:00
|
|
|
{
|
2016-01-08 20:53:57 -06:00
|
|
|
Log::warn("Note: LD_BIND_NOW is not set.");
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
Poco::Environment::get("LOK_VIEW_CALLBACK");
|
|
|
|
}
|
2015-12-25 12:50:53 -06:00
|
|
|
catch (const Poco::NotFoundException& exc)
|
2015-12-19 16:20:04 -06:00
|
|
|
{
|
2016-01-08 20:53:57 -06:00
|
|
|
Log::warn("Note: LOK_VIEW_CALLBACK is not set.");
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
|
2015-12-28 16:23:05 -06:00
|
|
|
// The loolkit binary must be in our directory.
|
|
|
|
const std::string loolkitPath = Poco::Path(argv[0]).parent().toString() + "loolkit";
|
|
|
|
if (!File(loolkitPath).exists())
|
|
|
|
{
|
|
|
|
Log::error("Error: loolkit does not exists at [" + loolkitPath + "].");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
2016-01-06 21:47:01 -06:00
|
|
|
const Path jailPath = Path::forDirectory(childRoot + Path::separator() + jailId);
|
2015-12-28 16:23:05 -06:00
|
|
|
Log::info("Jail path: " + jailPath.toString());
|
|
|
|
|
2015-12-19 19:09:48 -06:00
|
|
|
File(jailPath).createDirectories();
|
2015-12-19 16:20:04 -06:00
|
|
|
|
2015-12-19 19:09:48 -06:00
|
|
|
Path jailLOInstallation(jailPath, loSubPath);
|
2015-12-19 16:20:04 -06:00
|
|
|
jailLOInstallation.makeDirectory();
|
|
|
|
File(jailLOInstallation).createDirectory();
|
|
|
|
|
2015-12-28 16:23:05 -06:00
|
|
|
// Copy (link) LO installation and other necessary files into it from the template.
|
2015-12-19 19:09:48 -06:00
|
|
|
linkOrCopy(sysTemplate, jailPath);
|
2015-12-19 16:20:04 -06:00
|
|
|
linkOrCopy(loTemplate, jailLOInstallation);
|
|
|
|
|
|
|
|
// It is necessary to deploy loolkit process to chroot jail.
|
2015-12-28 16:23:05 -06:00
|
|
|
File(loolkitPath).copyTo(Path(jailPath, JAILED_LOOLKIT_PATH).toString());
|
2015-12-19 19:09:48 -06:00
|
|
|
|
|
|
|
// We need this because sometimes the hostname is not resolved
|
2016-01-03 13:52:32 -06:00
|
|
|
const std::vector<std::string> networkFiles = {"/etc/host.conf", "/etc/hosts", "/etc/nsswitch.conf", "/etc/resolv.conf"};
|
|
|
|
for (const auto& filename : networkFiles)
|
2015-12-19 19:09:48 -06:00
|
|
|
{
|
2016-01-03 13:52:32 -06:00
|
|
|
const File networkFile(filename);
|
2015-12-19 19:09:48 -06:00
|
|
|
if (networkFile.exists())
|
|
|
|
{
|
|
|
|
networkFile.copyTo(Path(jailPath, "/etc").toString());
|
|
|
|
}
|
|
|
|
}
|
2015-12-19 16:20:04 -06:00
|
|
|
|
|
|
|
#ifdef __linux
|
|
|
|
// Create the urandom and random devices
|
2015-12-19 19:09:48 -06:00
|
|
|
File(Path(jailPath, "/dev")).createDirectory();
|
|
|
|
if (mknod((jailPath.toString() + "/dev/random").c_str(),
|
2015-12-19 16:20:04 -06:00
|
|
|
S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH,
|
|
|
|
makedev(1, 8)) != 0)
|
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Error: mknod(" + jailPath.toString() + "/dev/random) failed.");
|
2015-12-19 16:20:04 -06:00
|
|
|
|
|
|
|
}
|
2015-12-19 19:09:48 -06:00
|
|
|
if (mknod((jailPath.toString() + "/dev/urandom").c_str(),
|
2015-12-19 16:20:04 -06:00
|
|
|
S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH,
|
|
|
|
makedev(1, 9)) != 0)
|
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Error: mknod(" + jailPath.toString() + "/dev/urandom) failed.");
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::info("loolbroker -> chroot(\"" + jailPath.toString() + "\")");
|
2015-12-19 19:09:48 -06:00
|
|
|
if (chroot(jailPath.toString().c_str()) == -1)
|
2015-12-19 16:20:04 -06:00
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Error: chroot(\"" + jailPath.toString() + "\") failed.");
|
2015-12-19 16:20:04 -06:00
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (chdir("/") == -1)
|
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Error: chdir(\"/\") in jail failed.");
|
2015-12-19 16:20:04 -06:00
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __linux
|
|
|
|
dropCapability(CAP_SYS_CHROOT);
|
2015-12-19 19:09:48 -06:00
|
|
|
dropCapability(CAP_MKNOD);
|
|
|
|
dropCapability(CAP_FOWNER);
|
2015-12-19 16:20:04 -06:00
|
|
|
#else
|
|
|
|
dropCapability();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (mkfifo(FIFO_BROKER.c_str(), 0666) == -1)
|
|
|
|
{
|
2015-12-25 12:50:53 -06:00
|
|
|
Log::error("Error: Failed to create pipe FIFO [" + FIFO_BROKER + "].");
|
2015-12-19 16:20:04 -06:00
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
2015-12-27 16:58:52 -06:00
|
|
|
const bool sharePages = globalPreinit(loSubPath);
|
2015-12-19 16:20:04 -06:00
|
|
|
|
2016-01-06 21:47:01 -06:00
|
|
|
if ( startupLibreOfficeKit(sharePages, numPreSpawnedChildren, loSubPath, jailId) < 0 )
|
2015-12-19 16:20:04 -06:00
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Error: failed to create children.");
|
2015-12-19 16:20:04 -06:00
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( (readerChild = open(FIFO_BROKER.c_str(), O_RDONLY) ) < 0 )
|
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Error: pipe opened for reading.");
|
2015-12-19 16:20:04 -06:00
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
PipeRunnable pipeHandler;
|
|
|
|
Poco::Thread aPipe;
|
|
|
|
|
|
|
|
aPipe.start(pipeHandler);
|
|
|
|
|
2015-12-29 18:59:17 -06:00
|
|
|
Log::info("loolbroker is ready.");
|
2015-12-28 15:34:21 -06:00
|
|
|
|
|
|
|
unsigned timeoutCounter = 0;
|
2015-12-28 17:24:29 -06:00
|
|
|
while (!TerminationFlag && !_childProcesses.empty())
|
2015-12-19 16:20:04 -06:00
|
|
|
{
|
|
|
|
int status;
|
2016-01-04 18:51:03 -06:00
|
|
|
const pid_t pid = waitpid(-1, &status, WUNTRACED | WNOHANG);
|
2015-12-19 16:20:04 -06:00
|
|
|
if (pid > 0)
|
|
|
|
{
|
|
|
|
if ( _childProcesses.find(pid) != _childProcesses.end() )
|
|
|
|
{
|
|
|
|
if ((WIFEXITED(status) || WIFSIGNALED(status) || WTERMSIG(status) ) )
|
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Child [" + std::to_string(pid) + "] processes died.");
|
2015-12-29 18:59:17 -06:00
|
|
|
|
2015-12-19 16:20:04 -06:00
|
|
|
forkMutex.lock();
|
|
|
|
_childProcesses.erase(pid);
|
|
|
|
_cacheURL.clear();
|
|
|
|
forkMutex.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( WCOREDUMP(status) )
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Child [" + std::to_string(pid) + "] produced a core dump.");
|
2015-12-19 16:20:04 -06:00
|
|
|
|
|
|
|
if ( WIFSTOPPED(status) )
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Child [" + std::to_string(pid) + "] process was stopped by delivery of a signal.");
|
2015-12-19 16:20:04 -06:00
|
|
|
|
|
|
|
if ( WSTOPSIG(status) )
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Child [" + std::to_string(pid) + "] process was stopped.");
|
2015-12-19 16:20:04 -06:00
|
|
|
|
|
|
|
if ( WIFCONTINUED(status) )
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Child [" + std::to_string(pid) + "] process was resumed.");
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("None of our known child processes died. PID: " + std::to_string(pid));
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (pid < 0)
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::error("Error: Child error.");
|
2015-12-19 16:20:04 -06:00
|
|
|
|
2016-01-05 06:51:05 -06:00
|
|
|
if (forkCounter > 0)
|
2015-12-19 16:20:04 -06:00
|
|
|
{
|
|
|
|
forkMutex.lock();
|
2016-01-06 09:08:54 -06:00
|
|
|
--forkCounter;
|
2015-12-19 16:20:04 -06:00
|
|
|
|
2016-01-06 21:47:01 -06:00
|
|
|
if (createLibreOfficeKit(sharePages, loSubPath, jailId) < 0)
|
2016-01-06 04:11:23 -06:00
|
|
|
Log::error("Error: fork failed.");
|
2015-12-19 16:20:04 -06:00
|
|
|
|
|
|
|
forkMutex.unlock();
|
|
|
|
}
|
|
|
|
|
2015-12-28 15:34:21 -06:00
|
|
|
if (timeoutCounter++ == INTERVAL_PROBES)
|
2015-12-19 16:20:04 -06:00
|
|
|
{
|
|
|
|
timeoutCounter = 0;
|
|
|
|
sleep(MAINTENANCE_INTERVAL);
|
2016-01-08 17:02:09 -06:00
|
|
|
maintenance.store( ++maintenance.load() );
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Terminate child processes
|
|
|
|
for (auto i : _childProcesses)
|
|
|
|
{
|
2015-12-24 21:19:50 -06:00
|
|
|
Log::info("Requesting child process " + std::to_string(i.first) + " to terminate.");
|
2015-12-29 18:59:17 -06:00
|
|
|
close(i.second);
|
2016-01-08 21:34:34 -06:00
|
|
|
Process::requestTermination(i.first);
|
|
|
|
if (!waitForTerminationChild(i.first))
|
|
|
|
{
|
|
|
|
Log::info("Forcing a child process " + std::to_string(i.first) + " to terminate.");
|
|
|
|
Process::kill(i.first);
|
|
|
|
}
|
2015-12-19 16:20:04 -06:00
|
|
|
}
|
|
|
|
|
2015-12-29 18:59:17 -06:00
|
|
|
aPipe.join();
|
|
|
|
close(readerChild);
|
|
|
|
close(readerBroker);
|
|
|
|
|
2015-12-28 22:39:25 -06:00
|
|
|
Log::info("Process [loolbroker] finished.");
|
2015-12-19 16:20:04 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|