Merge branch 'nix'.
This is a squashed commit of the following: commit 0dccab9f417b406f5d4aedc81900fc7b2f16c9f6 Author: Eelco Dolstra <eelco.dolstra@logicblox.com> Date: Thu Jul 2 00:30:16 2015 +0200 Typo commit 2cd28517b13524c242c7758783b0b2d8250fdded Author: Ludovic Courtès <ludo@gnu.org> Date: Wed Jul 1 14:56:34 2015 +0200 Preserve supplementary groups of build users The following patch is an attempt to address this bug (see <http://bugs.gnu.org/18994>) by preserving the supplementary groups of build users in the build environment. In practice, I would expect that supplementary groups would contain only one or two groups: the build users group, and possibly the “kvm” group. [Changed &at(0) to data() and removed tabs - Eelco] commit 6e38685ef65284093df79ebe7378bac33b0e7e5d Author: Eelco Dolstra <eelco.dolstra@logicblox.com> Date: Tue Jun 30 21:41:26 2015 +0200 GC: Handle ENOSPC creating/moving to the trash directory Issue #564. commit 5e0a9ae2e25a1016389f4893a6ed6682aadcf51d Author: Eelco Dolstra <eelco.dolstra@logicblox.com> Date: Mon Jun 22 15:54:55 2015 +0200 Use posix_fallocate to create /nix/var/nix/db/reserved commit 4e5ab98d6d14f8b0e3bd1d77b2f4f2354e7a49a8 Author: Eelco Dolstra <eelco.dolstra@logicblox.com> Date: Mon Jun 22 15:47:40 2015 +0200 Make /nix/var/nix/db/reserved bigger Issue #564. commit 60bda60fc06135aa97a93301b1a9e2270768f5b3 Author: Eelco Dolstra <eelco.dolstra@logicblox.com> Date: Wed Jun 10 16:17:06 2015 +0200 Export outputPaths function This is useful for the new hydra-queue-runner. commit 5dfea34048aa8541f20aeb2fbcd163561b609a49 Author: Eelco Dolstra <eelco.dolstra@logicblox.com> Date: Thu Jul 2 22:51:33 2015 +0200 Use std::vector::data() commit 2459458bc8257734ca78cb7a2db3df20bd730ec0 Author: Eelco Dolstra <eelco.dolstra@logicblox.com> Date: Thu Jun 4 16:04:41 2015 +0200 Allow substitutes for builds that have preferLocalBuild set Not substituting builds with "preferLocalBuild = true" was a bad idea, because it didn't take the cost of dependencies into account. For instance, if we can't substitute a fetchgit call, then we have to download/build git and all its dependencies. Partially reverts 5558652709f27e8a887580b77b93c705659d7a4b and adds a new derivation attribute "allowSubstitutes" to specify whether a derivation may be substituted.
This commit is contained in:
parent
d2cef629fd
commit
322eeb87d0
|
@ -447,6 +447,7 @@ private:
|
||||||
string user;
|
string user;
|
||||||
uid_t uid;
|
uid_t uid;
|
||||||
gid_t gid;
|
gid_t gid;
|
||||||
|
std::vector<gid_t> supplementaryGIDs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UserLock();
|
UserLock();
|
||||||
|
@ -460,6 +461,7 @@ public:
|
||||||
string getUser() { return user; }
|
string getUser() { return user; }
|
||||||
uid_t getUID() { return uid; }
|
uid_t getUID() { return uid; }
|
||||||
uid_t getGID() { return gid; }
|
uid_t getGID() { return gid; }
|
||||||
|
std::vector<gid_t> getSupplementaryGIDs() { return supplementaryGIDs; }
|
||||||
|
|
||||||
bool enabled() { return uid != 0; }
|
bool enabled() { return uid != 0; }
|
||||||
|
|
||||||
|
@ -539,6 +541,17 @@ void UserLock::acquire()
|
||||||
throw Error(format("the Nix user should not be a member of `%1%'")
|
throw Error(format("the Nix user should not be a member of `%1%'")
|
||||||
% settings.buildUsersGroup);
|
% settings.buildUsersGroup);
|
||||||
|
|
||||||
|
/* Get the list of supplementary groups of this build user. This
|
||||||
|
is usually either empty or contains a group such as "kvm". */
|
||||||
|
supplementaryGIDs.resize(10);
|
||||||
|
int ngroups = supplementaryGIDs.size();
|
||||||
|
int err = getgrouplist(pw->pw_name, pw->pw_gid,
|
||||||
|
supplementaryGIDs.data(), &ngroups);
|
||||||
|
if (err == -1)
|
||||||
|
throw Error(format("failed to get list of supplementary groups for ‘%1%’") % pw->pw_name);
|
||||||
|
|
||||||
|
supplementaryGIDs.resize(ngroups);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1000,7 +1013,7 @@ void DerivationGoal::haveDerivation()
|
||||||
/* We are first going to try to create the invalid output paths
|
/* We are first going to try to create the invalid output paths
|
||||||
through substitutes. If that doesn't work, we'll build
|
through substitutes. If that doesn't work, we'll build
|
||||||
them. */
|
them. */
|
||||||
if (settings.useSubstitutes && !willBuildLocally(drv))
|
if (settings.useSubstitutes && substitutesAllowed(drv))
|
||||||
foreach (PathSet::iterator, i, invalidOutputs)
|
foreach (PathSet::iterator, i, invalidOutputs)
|
||||||
addWaitee(worker.makeSubstitutionGoal(*i, buildMode == bmRepair));
|
addWaitee(worker.makeSubstitutionGoal(*i, buildMode == bmRepair));
|
||||||
|
|
||||||
|
@ -1188,22 +1201,6 @@ void DerivationGoal::inputsRealised()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PathSet outputPaths(const DerivationOutputs & outputs)
|
|
||||||
{
|
|
||||||
PathSet paths;
|
|
||||||
foreach (DerivationOutputs::const_iterator, i, outputs)
|
|
||||||
paths.insert(i->second.path);
|
|
||||||
return paths;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static string get(const StringPairs & map, const string & key)
|
|
||||||
{
|
|
||||||
StringPairs::const_iterator i = map.find(key);
|
|
||||||
return i == map.end() ? (string) "" : i->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool canBuildLocally(const string & platform)
|
static bool canBuildLocally(const string & platform)
|
||||||
{
|
{
|
||||||
return platform == settings.thisSystem
|
return platform == settings.thisSystem
|
||||||
|
@ -1214,12 +1211,25 @@ static bool canBuildLocally(const string & platform)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static string get(const StringPairs & map, const string & key, const string & def = "")
|
||||||
|
{
|
||||||
|
StringPairs::const_iterator i = map.find(key);
|
||||||
|
return i == map.end() ? def : i->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool willBuildLocally(const Derivation & drv)
|
bool willBuildLocally(const Derivation & drv)
|
||||||
{
|
{
|
||||||
return get(drv.env, "preferLocalBuild") == "1" && canBuildLocally(drv.platform);
|
return get(drv.env, "preferLocalBuild") == "1" && canBuildLocally(drv.platform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool substitutesAllowed(const Derivation & drv)
|
||||||
|
{
|
||||||
|
return get(drv.env, "allowSubstitutes", "1") == "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DerivationGoal::tryToBuild()
|
void DerivationGoal::tryToBuild()
|
||||||
{
|
{
|
||||||
trace("trying to build");
|
trace("trying to build");
|
||||||
|
@ -1242,7 +1252,7 @@ void DerivationGoal::tryToBuild()
|
||||||
can't acquire the lock, then continue; hopefully some other
|
can't acquire the lock, then continue; hopefully some other
|
||||||
goal can start a build, and if not, the main loop will sleep a
|
goal can start a build, and if not, the main loop will sleep a
|
||||||
few seconds and then retry this goal. */
|
few seconds and then retry this goal. */
|
||||||
if (!outputLocks.lockPaths(outputPaths(drv.outputs), "", false)) {
|
if (!outputLocks.lockPaths(outputPaths(drv), "", false)) {
|
||||||
worker.waitForAWhile(shared_from_this());
|
worker.waitForAWhile(shared_from_this());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1263,7 +1273,7 @@ void DerivationGoal::tryToBuild()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
missingPaths = outputPaths(drv.outputs);
|
missingPaths = outputPaths(drv);
|
||||||
if (buildMode != bmCheck)
|
if (buildMode != bmCheck)
|
||||||
foreach (PathSet::iterator, i, validPaths) missingPaths.erase(*i);
|
foreach (PathSet::iterator, i, validPaths) missingPaths.erase(*i);
|
||||||
|
|
||||||
|
@ -2168,7 +2178,6 @@ void DerivationGoal::runChild()
|
||||||
Strings envStrs;
|
Strings envStrs;
|
||||||
foreach (Environment::const_iterator, i, env)
|
foreach (Environment::const_iterator, i, env)
|
||||||
envStrs.push_back(rewriteHashes(i->first + "=" + i->second, rewritesToTmp));
|
envStrs.push_back(rewriteHashes(i->first + "=" + i->second, rewritesToTmp));
|
||||||
auto envArr = stringsToCharPtrs(envStrs);
|
|
||||||
|
|
||||||
/* If we are running in `build-users' mode, then switch to the
|
/* If we are running in `build-users' mode, then switch to the
|
||||||
user we allocated above. Make sure that we drop all root
|
user we allocated above. Make sure that we drop all root
|
||||||
|
@ -2177,10 +2186,11 @@ void DerivationGoal::runChild()
|
||||||
setuid() when run as root sets the real, effective and
|
setuid() when run as root sets the real, effective and
|
||||||
saved UIDs. */
|
saved UIDs. */
|
||||||
if (buildUser.enabled()) {
|
if (buildUser.enabled()) {
|
||||||
printMsg(lvlChatty, format("switching to user `%1%'") % buildUser.getUser());
|
/* Preserve supplementary groups of the build user, to allow
|
||||||
|
admins to specify groups such as "kvm". */
|
||||||
if (setgroups(0, 0) == -1)
|
if (setgroups(buildUser.getSupplementaryGIDs().size(),
|
||||||
throw SysError("cannot clear the set of supplementary groups");
|
buildUser.getSupplementaryGIDs().data()) == -1)
|
||||||
|
throw SysError("cannot set supplementary groups of build user");
|
||||||
|
|
||||||
if (setgid(buildUser.getGID()) == -1 ||
|
if (setgid(buildUser.getGID()) == -1 ||
|
||||||
getgid() != buildUser.getGID() ||
|
getgid() != buildUser.getGID() ||
|
||||||
|
@ -2199,7 +2209,6 @@ void DerivationGoal::runChild()
|
||||||
args.push_back(builderBasename);
|
args.push_back(builderBasename);
|
||||||
foreach (Strings::iterator, i, drv.args)
|
foreach (Strings::iterator, i, drv.args)
|
||||||
args.push_back(rewriteHashes(*i, rewritesToTmp));
|
args.push_back(rewriteHashes(*i, rewritesToTmp));
|
||||||
auto argArr = stringsToCharPtrs(args);
|
|
||||||
|
|
||||||
restoreSIGPIPE();
|
restoreSIGPIPE();
|
||||||
|
|
||||||
|
@ -2207,7 +2216,7 @@ void DerivationGoal::runChild()
|
||||||
writeFull(STDERR_FILENO, "\n");
|
writeFull(STDERR_FILENO, "\n");
|
||||||
|
|
||||||
/* Execute the program. This should not return. */
|
/* Execute the program. This should not return. */
|
||||||
execve(drv.builder.c_str(), (char * *) &argArr[0], (char * *) &envArr[0]);
|
execve(drv.builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data());
|
||||||
|
|
||||||
throw SysError(format("executing `%1%'") % drv.builder);
|
throw SysError(format("executing `%1%'") % drv.builder);
|
||||||
|
|
||||||
|
@ -2837,7 +2846,6 @@ void SubstitutionGoal::tryToRun()
|
||||||
args.push_back("--substitute");
|
args.push_back("--substitute");
|
||||||
args.push_back(storePath);
|
args.push_back(storePath);
|
||||||
args.push_back(destPath);
|
args.push_back(destPath);
|
||||||
auto argArr = stringsToCharPtrs(args);
|
|
||||||
|
|
||||||
/* Fork the substitute program. */
|
/* Fork the substitute program. */
|
||||||
pid = startProcess([&]() {
|
pid = startProcess([&]() {
|
||||||
|
@ -2847,7 +2855,7 @@ void SubstitutionGoal::tryToRun()
|
||||||
if (dup2(outPipe.writeSide, STDOUT_FILENO) == -1)
|
if (dup2(outPipe.writeSide, STDOUT_FILENO) == -1)
|
||||||
throw SysError("cannot dup output pipe into stdout");
|
throw SysError("cannot dup output pipe into stdout");
|
||||||
|
|
||||||
execv(sub.c_str(), (char * *) &argArr[0]);
|
execv(sub.c_str(), stringsToCharPtrs(args).data());
|
||||||
|
|
||||||
throw SysError(format("executing `%1%'") % sub);
|
throw SysError(format("executing `%1%'") % sub);
|
||||||
});
|
});
|
||||||
|
|
|
@ -285,4 +285,13 @@ bool wantOutput(const string & output, const std::set<string> & wanted)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PathSet outputPaths(const Derivation & drv)
|
||||||
|
{
|
||||||
|
PathSet paths;
|
||||||
|
for (auto & i : drv.outputs)
|
||||||
|
paths.insert(i.second.path);
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,5 +89,6 @@ Path makeDrvPathWithOutputs(const Path & drvPath, const std::set<string> & outpu
|
||||||
|
|
||||||
bool wantOutput(const string & output, const std::set<string> & wanted);
|
bool wantOutput(const string & output, const std::set<string> & wanted);
|
||||||
|
|
||||||
|
PathSet outputPaths(const Derivation & drv);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -376,6 +376,7 @@ struct LocalStore::GCState
|
||||||
bool gcKeepOutputs;
|
bool gcKeepOutputs;
|
||||||
bool gcKeepDerivations;
|
bool gcKeepDerivations;
|
||||||
unsigned long long bytesInvalidated;
|
unsigned long long bytesInvalidated;
|
||||||
|
bool moveToTrash = true;
|
||||||
Path trashDir;
|
Path trashDir;
|
||||||
bool shouldDelete;
|
bool shouldDelete;
|
||||||
GCState(GCResults & results_) : results(results_), bytesInvalidated(0) { }
|
GCState(GCResults & results_) : results(results_), bytesInvalidated(0) { }
|
||||||
|
@ -428,16 +429,23 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path)
|
||||||
not holding the global GC lock) we can delete the path without
|
not holding the global GC lock) we can delete the path without
|
||||||
being afraid that the path has become alive again. Otherwise
|
being afraid that the path has become alive again. Otherwise
|
||||||
delete it right away. */
|
delete it right away. */
|
||||||
if (S_ISDIR(st.st_mode)) {
|
if (state.moveToTrash && S_ISDIR(st.st_mode)) {
|
||||||
// Estimate the amount freed using the narSize field. FIXME:
|
// Estimate the amount freed using the narSize field. FIXME:
|
||||||
// if the path was not valid, need to determine the actual
|
// if the path was not valid, need to determine the actual
|
||||||
// size.
|
// size.
|
||||||
state.bytesInvalidated += size;
|
try {
|
||||||
if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1)
|
if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1)
|
||||||
throw SysError(format("making `%1%' writable") % path);
|
throw SysError(format("making `%1%' writable") % path);
|
||||||
Path tmp = state.trashDir + "/" + baseNameOf(path);
|
Path tmp = state.trashDir + "/" + baseNameOf(path);
|
||||||
if (rename(path.c_str(), tmp.c_str()))
|
if (rename(path.c_str(), tmp.c_str()))
|
||||||
throw SysError(format("unable to rename `%1%' to `%2%'") % path % tmp);
|
throw SysError(format("unable to rename `%1%' to `%2%'") % path % tmp);
|
||||||
|
state.bytesInvalidated += size;
|
||||||
|
} catch (SysError & e) {
|
||||||
|
if (e.errNo == ENOSPC) {
|
||||||
|
printMsg(lvlInfo, format("note: can't create move `%1%': %2%") % path % e.msg());
|
||||||
|
deleteGarbage(state, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
deleteGarbage(state, path);
|
deleteGarbage(state, path);
|
||||||
|
|
||||||
|
@ -636,7 +644,14 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||||
|
|
||||||
if (state.shouldDelete) {
|
if (state.shouldDelete) {
|
||||||
if (pathExists(state.trashDir)) deleteGarbage(state, state.trashDir);
|
if (pathExists(state.trashDir)) deleteGarbage(state, state.trashDir);
|
||||||
createDirs(state.trashDir);
|
try {
|
||||||
|
createDirs(state.trashDir);
|
||||||
|
} catch (SysError & e) {
|
||||||
|
if (e.errNo == ENOSPC) {
|
||||||
|
printMsg(lvlInfo, format("note: can't create trash directory: %1%") % e.msg());
|
||||||
|
state.moveToTrash = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now either delete all garbage paths, or just the specified
|
/* Now either delete all garbage paths, or just the specified
|
||||||
|
|
|
@ -36,7 +36,7 @@ Settings::Settings()
|
||||||
buildTimeout = 0;
|
buildTimeout = 0;
|
||||||
useBuildHook = true;
|
useBuildHook = true;
|
||||||
printBuildTrace = false;
|
printBuildTrace = false;
|
||||||
reservedSize = 1024 * 1024;
|
reservedSize = 8 * 1024 * 1024;
|
||||||
fsyncMetadata = true;
|
fsyncMetadata = true;
|
||||||
useSQLiteWAL = true;
|
useSQLiteWAL = true;
|
||||||
syncBeforeRegistering = false;
|
syncBeforeRegistering = false;
|
||||||
|
|
|
@ -288,7 +288,17 @@ LocalStore::LocalStore(bool reserveSpace)
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (stat(reservedPath.c_str(), &st) == -1 ||
|
if (stat(reservedPath.c_str(), &st) == -1 ||
|
||||||
st.st_size != settings.reservedSize)
|
st.st_size != settings.reservedSize)
|
||||||
writeFile(reservedPath, string(settings.reservedSize, 'X'));
|
{
|
||||||
|
AutoCloseFD fd = open(reservedPath.c_str(), O_WRONLY | O_CREAT, 0600);
|
||||||
|
int res = -1;
|
||||||
|
#if HAVE_POSIX_FALLOCATE
|
||||||
|
res = posix_fallocate(fd, 0, settings.reservedSize);
|
||||||
|
#endif
|
||||||
|
if (res == -1) {
|
||||||
|
writeFull(fd, string(settings.reservedSize, 'X'));
|
||||||
|
ftruncate(fd, settings.reservedSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
deletePath(reservedPath);
|
deletePath(reservedPath);
|
||||||
|
@ -1166,10 +1176,8 @@ string LocalStore::getLineFromSubstituter(RunningSubstituter & run)
|
||||||
if (n == 0) throw EndOfFile(format("substituter `%1%' died unexpectedly") % run.program);
|
if (n == 0) throw EndOfFile(format("substituter `%1%' died unexpectedly") % run.program);
|
||||||
err.append(buf, n);
|
err.append(buf, n);
|
||||||
string::size_type p;
|
string::size_type p;
|
||||||
while (((p = err.find('\n')) != string::npos)
|
while ((p = err.find('\n')) != string::npos) {
|
||||||
|| ((p = err.find('\r')) != string::npos)) {
|
printMsg(lvlError, run.program + ": " + string(err, 0, p));
|
||||||
string thing(err, 0, p + 1);
|
|
||||||
writeToStderr(run.program + ": " + thing);
|
|
||||||
err = string(err, p + 1);
|
err = string(err, p + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,7 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
|
||||||
if (invalid.empty()) continue;
|
if (invalid.empty()) continue;
|
||||||
|
|
||||||
todoDrv.insert(*i);
|
todoDrv.insert(*i);
|
||||||
if (settings.useSubstitutes && !willBuildLocally(drv))
|
if (settings.useSubstitutes && substitutesAllowed(drv))
|
||||||
query.insert(invalid.begin(), invalid.end());
|
query.insert(invalid.begin(), invalid.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
|
||||||
|
|
||||||
PathSet outputs;
|
PathSet outputs;
|
||||||
bool mustBuild = false;
|
bool mustBuild = false;
|
||||||
if (settings.useSubstitutes && !willBuildLocally(drv)) {
|
if (settings.useSubstitutes && substitutesAllowed(drv)) {
|
||||||
foreach (DerivationOutputs::iterator, j, drv.outputs) {
|
foreach (DerivationOutputs::iterator, j, drv.outputs) {
|
||||||
if (!wantOutput(j->first, i2.second)) continue;
|
if (!wantOutput(j->first, i2.second)) continue;
|
||||||
if (!store.isValidPath(j->second.path)) {
|
if (!store.isValidPath(j->second.path)) {
|
||||||
|
|
|
@ -34,5 +34,7 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
|
||||||
|
|
||||||
bool willBuildLocally(const Derivation & drv);
|
bool willBuildLocally(const Derivation & drv);
|
||||||
|
|
||||||
|
bool substitutesAllowed(const Derivation & drv);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -897,10 +897,10 @@ pid_t startProcess(std::function<void()> fun,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::vector<const char *> stringsToCharPtrs(const Strings & ss)
|
std::vector<char *> stringsToCharPtrs(const Strings & ss)
|
||||||
{
|
{
|
||||||
std::vector<const char *> res;
|
std::vector<char *> res;
|
||||||
for (auto & s : ss) res.push_back(s.c_str());
|
for (auto & s : ss) res.push_back((char *) s.c_str());
|
||||||
res.push_back(0);
|
res.push_back(0);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -921,12 +921,11 @@ string runProgram(Path program, bool searchPath, const Strings & args)
|
||||||
|
|
||||||
Strings args_(args);
|
Strings args_(args);
|
||||||
args_.push_front(program);
|
args_.push_front(program);
|
||||||
auto cargs = stringsToCharPtrs(args_);
|
|
||||||
|
|
||||||
if (searchPath)
|
if (searchPath)
|
||||||
execvp(program.c_str(), (char * *) &cargs[0]);
|
execvp(program.c_str(), stringsToCharPtrs(args_).data());
|
||||||
else
|
else
|
||||||
execv(program.c_str(), (char * *) &cargs[0]);
|
execv(program.c_str(), stringsToCharPtrs(args_).data());
|
||||||
|
|
||||||
throw SysError(format("executing `%1%'") % program);
|
throw SysError(format("executing `%1%'") % program);
|
||||||
});
|
});
|
||||||
|
|
|
@ -284,7 +284,7 @@ MakeError(ExecError, Error)
|
||||||
/* Convert a list of strings to a null-terminated vector of char
|
/* Convert a list of strings to a null-terminated vector of char
|
||||||
*'s. The result must not be accessed beyond the lifetime of the
|
*'s. The result must not be accessed beyond the lifetime of the
|
||||||
list of strings. */
|
list of strings. */
|
||||||
std::vector<const char *> stringsToCharPtrs(const Strings & ss);
|
std::vector<char *> stringsToCharPtrs(const Strings & ss);
|
||||||
|
|
||||||
/* Close all file descriptors except stdin, stdout, stderr, and those
|
/* Close all file descriptors except stdin, stdout, stderr, and those
|
||||||
listed in the given set. Good practice in child processes. */
|
listed in the given set. Good practice in child processes. */
|
||||||
|
|
|
@ -440,10 +440,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
||||||
case wopImportPaths: {
|
case wopImportPaths: {
|
||||||
startWork();
|
startWork();
|
||||||
TunnelSource source(from);
|
TunnelSource source(from);
|
||||||
|
Paths paths = store->importPaths(!trusted, source);
|
||||||
/* Unlike Nix, always require a signature, even for "trusted"
|
|
||||||
users. */
|
|
||||||
Paths paths = store->importPaths(true, source);
|
|
||||||
stopWork();
|
stopWork();
|
||||||
writeStrings(paths, to);
|
writeStrings(paths, to);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue