aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libexpr/primops.cc15
-rw-r--r--src/libstore/build.cc83
-rw-r--r--src/libstore/gc.cc7
-rw-r--r--src/libutil/util.cc14
-rw-r--r--src/libutil/util.hh7
-rwxr-xr-xsrc/nix-build/nix-build.cc12
-rw-r--r--src/nix/repl.cc40
7 files changed, 140 insertions, 38 deletions
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 39073725e..06f577f36 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -923,6 +923,20 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
mkPath(v, state.checkSourcePath(state.findFile(searchPath, path, pos)).c_str());
}
+/* Return the cryptographic hash of a file in base-16. */
+static void prim_hashFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
+{
+ string type = state.forceStringNoCtx(*args[0], pos);
+ HashType ht = parseHashType(type);
+ if (ht == htUnknown)
+ throw Error(format("unknown hash type '%1%', at %2%") % type % pos);
+
+ PathSet context; // discarded
+ Path p = state.coerceToPath(pos, *args[1], context);
+
+ mkString(v, hashFile(ht, state.checkSourcePath(p)).to_string(Base16, false), context);
+}
+
/* Read a directory (without . or ..) */
static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
@@ -2202,6 +2216,7 @@ void EvalState::createBaseEnv()
addPrimOp("__readFile", 1, prim_readFile);
addPrimOp("__readDir", 1, prim_readDir);
addPrimOp("__findFile", 2, prim_findFile);
+ addPrimOp("__hashFile", 2, prim_hashFile);
// Creating files
addPrimOp("__toXML", 1, prim_toXML);
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index dbadfacd5..0bd738809 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -461,6 +461,28 @@ static void commonChildInit(Pipe & logPipe)
close(fdDevNull);
}
+void handleDiffHook(uid_t uid, uid_t gid, Path tryA, Path tryB, Path drvPath, Path tmpDir)
+{
+ auto diffHook = settings.diffHook;
+ if (diffHook != "" && settings.runDiffHook) {
+ try {
+ RunOptions diffHookOptions(diffHook,{tryA, tryB, drvPath, tmpDir});
+ diffHookOptions.searchPath = true;
+ diffHookOptions.uid = uid;
+ diffHookOptions.gid = gid;
+ diffHookOptions.chdir = "/";
+
+ auto diffRes = runProgram(diffHookOptions);
+ if (!statusOk(diffRes.first))
+ throw ExecError(diffRes.first, fmt("diff-hook program '%1%' %2%", diffHook, statusToString(diffRes.first)));
+
+ if (diffRes.second != "")
+ printError(chomp(diffRes.second));
+ } catch (Error & error) {
+ printError("diff hook execution failed: %s", error.what());
+ }
+ }
+}
//////////////////////////////////////////////////////////////////////
@@ -803,9 +825,6 @@ private:
/* Whether we're currently doing a chroot build. */
bool useChroot = false;
- /* Whether we need to perform hash rewriting if there are valid output paths. */
- bool needsHashRewrite;
-
Path chrootRootDir;
/* RAII object to delete the chroot directory. */
@@ -885,6 +904,9 @@ public:
Worker & worker, BuildMode buildMode = bmNormal);
~DerivationGoal();
+ /* Whether we need to perform hash rewriting if there are valid output paths. */
+ bool needsHashRewrite();
+
void timedOut() override;
string key() override
@@ -997,13 +1019,6 @@ DerivationGoal::DerivationGoal(const Path & drvPath, const StringSet & wantedOut
, wantedOutputs(wantedOutputs)
, buildMode(buildMode)
{
-#if __linux__
- needsHashRewrite = !useChroot;
-#else
- /* Darwin requires hash rewriting even when sandboxing is enabled. */
- needsHashRewrite = true;
-#endif
-
state = &DerivationGoal::getDerivation;
name = (format("building of '%1%'") % drvPath).str();
trace("created");
@@ -1044,6 +1059,17 @@ DerivationGoal::~DerivationGoal()
}
+inline bool DerivationGoal::needsHashRewrite()
+{
+#if __linux__
+ return !useChroot;
+#else
+ /* Darwin requires hash rewriting even when sandboxing is enabled. */
+ return true;
+#endif
+}
+
+
void DerivationGoal::killChild()
{
if (pid != -1) {
@@ -2083,7 +2109,7 @@ void DerivationGoal::startBuilder()
#endif
}
- if (needsHashRewrite) {
+ if (needsHashRewrite()) {
if (pathExists(homeDir))
throw Error(format("directory '%1%' exists; please remove it") % homeDir);
@@ -2510,17 +2536,17 @@ void setupSeccomp()
seccomp_release(ctx);
});
- if (settings.thisSystem == "x86_64-linux" &&
+ if (nativeSystem == "x86_64-linux" &&
seccomp_arch_add(ctx, SCMP_ARCH_X86) != 0)
throw SysError("unable to add 32-bit seccomp architecture");
- if (settings.thisSystem == "x86_64-linux" &&
+ if (nativeSystem == "x86_64-linux" &&
seccomp_arch_add(ctx, SCMP_ARCH_X32) != 0)
throw SysError("unable to add X32 seccomp architecture");
- if (settings.thisSystem == "aarch64-linux" &&
+ if (nativeSystem == "aarch64-linux" &&
seccomp_arch_add(ctx, SCMP_ARCH_ARM) != 0)
- printError("unsable to add ARM seccomp architecture; this may result in spurious build failures if running 32-bit ARM processes.");
+ printError("unable to add ARM seccomp architecture; this may result in spurious build failures if running 32-bit ARM processes");
/* Prevent builders from creating setuid/setgid binaries. */
for (int perm : { S_ISUID, S_ISGID }) {
@@ -3039,8 +3065,7 @@ void DerivationGoal::registerOutputs()
InodesSeen inodesSeen;
Path checkSuffix = ".check";
- bool runDiffHook = settings.runDiffHook;
- bool keepPreviousRound = settings.keepFailed || runDiffHook;
+ bool keepPreviousRound = settings.keepFailed || settings.runDiffHook;
std::exception_ptr delayedException;
@@ -3067,7 +3092,7 @@ void DerivationGoal::registerOutputs()
if (buildMode != bmCheck) actualPath = worker.store.toRealPath(path);
}
- if (needsHashRewrite) {
+ if (needsHashRewrite()) {
Path redirected = redirectedOutputs[path];
if (buildMode == bmRepair
&& redirectedBadOutputs.find(path) != redirectedBadOutputs.end()
@@ -3185,11 +3210,17 @@ void DerivationGoal::registerOutputs()
if (!worker.store.isValidPath(path)) continue;
auto info = *worker.store.queryPathInfo(path);
if (hash.first != info.narHash) {
- if (settings.keepFailed) {
+ if (settings.runDiffHook || settings.keepFailed) {
Path dst = worker.store.toRealPath(path + checkSuffix);
deletePath(dst);
if (rename(actualPath.c_str(), dst.c_str()))
throw SysError(format("renaming '%1%' to '%2%'") % actualPath % dst);
+
+ handleDiffHook(
+ buildUser ? buildUser->getUID() : getuid(),
+ buildUser ? buildUser->getGID() : getgid(),
+ path, dst, drvPath, tmpDir);
+
throw Error(format("derivation '%1%' may not be deterministic: output '%2%' differs from '%3%'")
% drvPath % path % dst);
} else
@@ -3254,16 +3285,10 @@ void DerivationGoal::registerOutputs()
? fmt("output '%1%' of '%2%' differs from '%3%' from previous round", i->second.path, drvPath, prev)
: fmt("output '%1%' of '%2%' differs from previous round", i->second.path, drvPath);
- auto diffHook = settings.diffHook;
- if (prevExists && diffHook != "" && runDiffHook) {
- try {
- auto diff = runProgram(diffHook, true, {prev, i->second.path});
- if (diff != "")
- printError(chomp(diff));
- } catch (Error & error) {
- printError("diff hook execution failed: %s", error.what());
- }
- }
+ handleDiffHook(
+ buildUser ? buildUser->getUID() : getuid(),
+ buildUser ? buildUser->getGID() : getgid(),
+ prev, i->second.path, drvPath, tmpDir);
if (settings.enforceDeterminism)
throw NotDeterministic(msg);
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index d8a5da0d4..26e2b0dca 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -326,10 +326,9 @@ void LocalStore::findRootsNoTemp(Roots & roots, bool censor)
findRoots(stateDir + "/" + gcRootsDir, DT_UNKNOWN, roots);
findRoots(stateDir + "/profiles", DT_UNKNOWN, 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). */
+ /* Add additional roots returned by different platforms-specific
+ heuristics. This is typically used to add running programs to
+ the set of roots (to prevent them from being garbage collected). */
findRuntimeRoots(roots, censor);
}
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index e3dcd246c..17aee2d5c 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -16,6 +16,7 @@
#include <future>
#include <fcntl.h>
+#include <grp.h>
#include <limits.h>
#include <pwd.h>
#include <sys/ioctl.h>
@@ -38,6 +39,9 @@ extern char * * environ;
namespace nix {
+const std::string nativeSystem = SYSTEM;
+
+
BaseError & BaseError::addPrefix(const FormatOrString & fs)
{
prefix_ = fs.s + prefix_;
@@ -1022,6 +1026,16 @@ void runProgram2(const RunOptions & options)
if (source && dup2(in.readSide.get(), STDIN_FILENO) == -1)
throw SysError("dupping stdin");
+ if (options.chdir && chdir((*options.chdir).c_str()) == -1)
+ throw SysError("chdir failed");
+ if (options.gid && setgid(*options.gid) == -1)
+ throw SysError("setgid failed");
+ /* Drop all other groups if we're setgid. */
+ if (options.gid && setgroups(0, 0) == -1)
+ throw SysError("setgroups failed");
+ if (options.uid && setuid(*options.uid) == -1)
+ throw SysError("setuid failed");
+
Strings args_(options.args);
args_.push_front(options.program);
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 23360de2e..fce3cab8d 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -30,6 +30,10 @@ struct Sink;
struct Source;
+/* The system for which Nix is compiled. */
+extern const std::string nativeSystem;
+
+
/* Return an environment variable. */
string getEnv(const string & key, const string & def = "");
@@ -263,6 +267,9 @@ string runProgram(Path program, bool searchPath = false,
struct RunOptions
{
+ std::optional<uid_t> uid;
+ std::optional<uid_t> gid;
+ std::optional<Path> chdir;
Path program;
bool searchPath = true;
Strings args;
diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc
index 618895d38..c6a4d4166 100755
--- a/src/nix-build/nix-build.cc
+++ b/src/nix-build/nix-build.cc
@@ -274,19 +274,21 @@ static void _main(int argc, char * * argv)
exprs = {state->parseStdin()};
else
for (auto i : left) {
- auto absolute = i;
- try {
- absolute = canonPath(absPath(i), true);
- } catch (Error e) {};
if (fromArgs)
exprs.push_back(state->parseExprFromString(i, absPath(".")));
- else if (store->isStorePath(absolute) && std::regex_match(absolute, std::regex(".*\\.drv(!.*)?")))
+ else {
+ auto absolute = i;
+ try {
+ absolute = canonPath(absPath(i), true);
+ } catch (Error e) {};
+ if (store->isStorePath(absolute) && std::regex_match(absolute, std::regex(".*\\.drv(!.*)?")))
drvs.push_back(DrvInfo(*state, store, absolute));
else
/* If we're in a #! script, interpret filenames
relative to the script. */
exprs.push_back(state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state,
inShebang && !packages ? absPath(i, absPath(dirOf(script))) : i)))));
+ }
}
/* Evaluate them into derivations. */
diff --git a/src/nix/repl.cc b/src/nix/repl.cc
index 227affc60..d8f812149 100644
--- a/src/nix/repl.cc
+++ b/src/nix/repl.cc
@@ -192,6 +192,14 @@ static int listPossibleCallback(char *s, char ***avp) {
return ac;
}
+namespace {
+ // Used to communicate to NixRepl::getLine whether a signal occurred in ::readline.
+ volatile sig_atomic_t g_signal_received = 0;
+
+ void sigintHandler(int signo) {
+ g_signal_received = signo;
+ }
+}
void NixRepl::mainLoop(const std::vector<std::string> & files)
{
@@ -251,8 +259,40 @@ void NixRepl::mainLoop(const std::vector<std::string> & files)
bool NixRepl::getLine(string & input, const std::string &prompt)
{
+ struct sigaction act, old;
+ sigset_t savedSignalMask, set;
+
+ auto setupSignals = [&]() {
+ act.sa_handler = sigintHandler;
+ sigfillset(&act.sa_mask);
+ act.sa_flags = 0;
+ if (sigaction(SIGINT, &act, &old))
+ throw SysError("installing handler for SIGINT");
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGINT);
+ if (sigprocmask(SIG_UNBLOCK, &set, &savedSignalMask))
+ throw SysError("unblocking SIGINT");
+ };
+ auto restoreSignals = [&]() {
+ if (sigprocmask(SIG_SETMASK, &savedSignalMask, nullptr))
+ throw SysError("restoring signals");
+
+ if (sigaction(SIGINT, &old, 0))
+ throw SysError("restoring handler for SIGINT");
+ };
+
+ setupSignals();
char * s = readline(prompt.c_str());
Finally doFree([&]() { free(s); });
+ restoreSignals();
+
+ if (g_signal_received) {
+ g_signal_received = 0;
+ input.clear();
+ return true;
+ }
+
if (!s)
return false;
input += s;