forked from lix-project/lix
* Call find-runtime-roots.pl from the garbage collector to prevent
running applications etc. from being garbage collected.
This commit is contained in:
parent
ebcccbd358
commit
c15f544356
|
@ -66,6 +66,9 @@ irreversible.</para></warning>
|
||||||
<listitem><para>TODO: nix-pack-closure and
|
<listitem><para>TODO: nix-pack-closure and
|
||||||
nix-unpack-closure.</para></listitem>
|
nix-unpack-closure.</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>TODO: open files etc. are now used as roots of the
|
||||||
|
garbage collector.</para></listitem>
|
||||||
|
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -12,10 +12,6 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#ifdef __CYGWIN__
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
|
|
||||||
|
@ -321,13 +317,6 @@ const char * * strings2CharPtrs(const Strings & ss)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Hack for Cygwin: _exit() doesn't seem to work quite right, since
|
|
||||||
some Berkeley DB code appears to be called when a child exits
|
|
||||||
through _exit() (e.g., because execve() failed). So call the
|
|
||||||
Windows API directly. */
|
|
||||||
#ifdef __CYGWIN__
|
|
||||||
#define _exit(n) ExitProcess(n)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
@ -460,9 +449,9 @@ static void killUser(uid_t uid)
|
||||||
|
|
||||||
} catch (exception & e) {
|
} catch (exception & e) {
|
||||||
cerr << format("build error: %1%\n") % e.what();
|
cerr << format("build error: %1%\n") % e.what();
|
||||||
_exit(1);
|
quickExit(1);
|
||||||
}
|
}
|
||||||
_exit(0);
|
quickExit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parent */
|
/* parent */
|
||||||
|
@ -944,7 +933,7 @@ DerivationGoal::HookReply DerivationGoal::tryBuildHook()
|
||||||
} catch (exception & e) {
|
} catch (exception & e) {
|
||||||
cerr << format("build error: %1%\n") % e.what();
|
cerr << format("build error: %1%\n") % e.what();
|
||||||
}
|
}
|
||||||
_exit(1);
|
quickExit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parent */
|
/* parent */
|
||||||
|
@ -1340,7 +1329,7 @@ void DerivationGoal::startBuilder()
|
||||||
} catch (exception & e) {
|
} catch (exception & e) {
|
||||||
cerr << format("build error: %1%\n") % e.what();
|
cerr << format("build error: %1%\n") % e.what();
|
||||||
}
|
}
|
||||||
_exit(1);
|
quickExit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1779,7 +1768,7 @@ void SubstitutionGoal::tryToRun()
|
||||||
} catch (exception & e) {
|
} catch (exception & e) {
|
||||||
cerr << format("substitute error: %1%\n") % e.what();
|
cerr << format("substitute error: %1%\n") % e.what();
|
||||||
}
|
}
|
||||||
_exit(1);
|
quickExit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parent */
|
/* parent */
|
||||||
|
|
|
@ -316,6 +316,31 @@ static void findRoots(const Path & path, bool recurseSymlinks,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void addAdditionalRoots(PathSet & roots)
|
||||||
|
{
|
||||||
|
Path rootFinder = getEnv("NIX_ROOT_FINDER",
|
||||||
|
"/nix/libexec/nix/find-runtime-roots.pl"); /* !!! */
|
||||||
|
|
||||||
|
if (rootFinder.empty()) return;
|
||||||
|
|
||||||
|
printMsg(lvlDebug, format("executing `%1%' to find additional roots") % rootFinder);
|
||||||
|
|
||||||
|
string result = runProgram(rootFinder);
|
||||||
|
|
||||||
|
Strings paths = tokenizeString(result, "\n");
|
||||||
|
|
||||||
|
for (Strings::iterator i = paths.begin(); i != paths.end(); ++i) {
|
||||||
|
if (isInStore(*i)) {
|
||||||
|
Path path = toStorePath(*i);
|
||||||
|
if (roots.find(path) == roots.end()) {
|
||||||
|
debug(format("found additional root `%1%'") % path);
|
||||||
|
roots.insert(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void dfsVisit(const PathSet & paths, const Path & path,
|
static void dfsVisit(const PathSet & paths, const Path & path,
|
||||||
PathSet & visited, Paths & sorted)
|
PathSet & visited, Paths & sorted)
|
||||||
{
|
{
|
||||||
|
@ -370,6 +395,12 @@ void collectGarbage(GCAction action, const PathSet & pathsToDelete,
|
||||||
if (!ignoreLiveness)
|
if (!ignoreLiveness)
|
||||||
findRoots(rootsDir, true, roots);
|
findRoots(rootsDir, true, roots);
|
||||||
|
|
||||||
|
/* Add additional roots returned by the program specified by the
|
||||||
|
NIX_ROOT_FINDER environment variable. This is typically used
|
||||||
|
to add running programs to the set of roots (to prevent them
|
||||||
|
from being garbage collected). */
|
||||||
|
addAdditionalRoots(roots);
|
||||||
|
|
||||||
if (action == gcReturnRoots) {
|
if (action == gcReturnRoots) {
|
||||||
result = roots;
|
result = roots;
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -13,6 +13,10 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
|
||||||
|
|
||||||
|
@ -434,6 +438,23 @@ void writeFull(int fd, const unsigned char * buf, size_t count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string drainFD(int fd)
|
||||||
|
{
|
||||||
|
string result;
|
||||||
|
unsigned char buffer[4096];
|
||||||
|
while (1) {
|
||||||
|
ssize_t rd = read(fd, buffer, sizeof buffer);
|
||||||
|
if (rd == -1) {
|
||||||
|
if (errno != EINTR)
|
||||||
|
throw SysError("reading from file");
|
||||||
|
}
|
||||||
|
else if (rd == 0) break;
|
||||||
|
else result.append((char *) buffer, rd);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -643,6 +664,69 @@ void Pid::setSeparatePG(bool separatePG)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
string runProgram(Path program)
|
||||||
|
{
|
||||||
|
/* Create a pipe. */
|
||||||
|
Pipe pipe;
|
||||||
|
pipe.create();
|
||||||
|
|
||||||
|
/* Fork. */
|
||||||
|
Pid pid;
|
||||||
|
pid = fork();
|
||||||
|
switch (pid) {
|
||||||
|
|
||||||
|
case -1:
|
||||||
|
throw SysError("unable to fork");
|
||||||
|
|
||||||
|
case 0: /* child */
|
||||||
|
try {
|
||||||
|
pipe.readSide.close();
|
||||||
|
|
||||||
|
if (dup2(pipe.writeSide, STDOUT_FILENO) == -1)
|
||||||
|
throw SysError("dupping from-hook write side");
|
||||||
|
|
||||||
|
execl(program.c_str(), program.c_str(), (char *) 0);
|
||||||
|
throw SysError(format("executing `%1%'") % program);
|
||||||
|
|
||||||
|
} catch (exception & e) {
|
||||||
|
cerr << "error: " << e.what() << endl;
|
||||||
|
}
|
||||||
|
quickExit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parent. */
|
||||||
|
|
||||||
|
pipe.writeSide.close();
|
||||||
|
|
||||||
|
string result = drainFD(pipe.readSide);
|
||||||
|
|
||||||
|
/* Wait for the child to finish. */
|
||||||
|
int status = pid.wait(true);
|
||||||
|
if (!statusOk(status))
|
||||||
|
throw Error(format("program `%1% %2%")
|
||||||
|
% program % statusToString(status));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void quickExit(int status)
|
||||||
|
{
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
/* Hack for Cygwin: _exit() doesn't seem to work quite right,
|
||||||
|
since some Berkeley DB code appears to be called when a child
|
||||||
|
exits through _exit() (e.g., because execve() failed). So call
|
||||||
|
the Windows API directly. */
|
||||||
|
ExitProcess(status);
|
||||||
|
#else
|
||||||
|
_exit(status);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -185,6 +185,11 @@ void readFull(int fd, unsigned char * buf, size_t count);
|
||||||
void writeFull(int fd, const unsigned char * buf, size_t count);
|
void writeFull(int fd, const unsigned char * buf, size_t count);
|
||||||
|
|
||||||
|
|
||||||
|
/* Read a file descriptor until EOF occurs. */
|
||||||
|
string drainFD(int fd);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Automatic cleanup of resources. */
|
/* Automatic cleanup of resources. */
|
||||||
|
|
||||||
class AutoDelete
|
class AutoDelete
|
||||||
|
@ -249,6 +254,15 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Run a program and return its stdout in a string (i.e., like the
|
||||||
|
shell backtick operator). */
|
||||||
|
string runProgram(Path program);
|
||||||
|
|
||||||
|
/* Wrapper around _exit() on Unix and ExitProcess() on Windows. (On
|
||||||
|
Cygwin, _exit() doesn't seem to do the right thing.) */
|
||||||
|
void quickExit(int status);
|
||||||
|
|
||||||
|
|
||||||
/* User interruption. */
|
/* User interruption. */
|
||||||
|
|
||||||
extern volatile sig_atomic_t _isInterrupted;
|
extern volatile sig_atomic_t _isInterrupted;
|
||||||
|
|
|
@ -13,6 +13,7 @@ export NIX_DB_DIR=$TEST_ROOT/db
|
||||||
export NIX_CONF_DIR=$TEST_ROOT/etc
|
export NIX_CONF_DIR=$TEST_ROOT/etc
|
||||||
export NIX_BIN_DIR=$TEST_ROOT/bin
|
export NIX_BIN_DIR=$TEST_ROOT/bin
|
||||||
export NIX_LIBEXEC_DIR=$TEST_ROOT/bin
|
export NIX_LIBEXEC_DIR=$TEST_ROOT/bin
|
||||||
|
export NIX_ROOT_FINDER=
|
||||||
export SHARED=$TEST_ROOT/shared
|
export SHARED=$TEST_ROOT/shared
|
||||||
|
|
||||||
export REAL_BIN_DIR=@bindir@
|
export REAL_BIN_DIR=@bindir@
|
||||||
|
|
Loading…
Reference in a new issue