1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-13 14:02:42 +01:00

Merge branch 'errors-phase-2' of https://github.com/bburdette/nix

This commit is contained in:
Eelco Dolstra 2020-06-15 11:46:31 +02:00
commit 7a77762961
81 changed files with 1857 additions and 1010 deletions

View file

@ -40,14 +40,14 @@ void BinaryCacheStore::init()
upsertFile(cacheInfoFile, "StoreDir: " + storeDir + "\n", "text/x-nix-cache-info");
} else {
for (auto & line : tokenizeString<Strings>(*cacheInfo, "\n")) {
size_t colon = line.find(':');
if (colon == std::string::npos) continue;
size_t colon= line.find(':');
if (colon ==std::string::npos) continue;
auto name = line.substr(0, colon);
auto value = trim(line.substr(colon + 1, std::string::npos));
if (name == "StoreDir") {
if (value != storeDir)
throw Error(format("binary cache '%s' is for Nix stores with prefix '%s', not '%s'")
% getUri() % value % storeDir);
throw Error("binary cache '%s' is for Nix stores with prefix '%s', not '%s'",
getUri(), value, storeDir);
} else if (name == "WantMassQuery") {
wantMassQuery.setDefault(value == "1" ? "true" : "false");
} else if (name == "Priority") {
@ -287,7 +287,7 @@ void BinaryCacheStore::narFromPath(const StorePath & storePath, Sink & sink)
try {
getFile(info->url, *decompressor);
} catch (NoSuchBinaryCacheFile & e) {
throw SubstituteGone(e.what());
throw SubstituteGone(e.info());
}
decompressor->finish();

View file

@ -453,7 +453,7 @@ static void commonChildInit(Pipe & logPipe)
that e.g. ssh cannot open /dev/tty) and it doesn't receive
terminal signals. */
if (setsid() == -1)
throw SysError(format("creating a new session"));
throw SysError("creating a new session");
/* Dup the write side of the logger pipe into stderr. */
if (dup2(logPipe.writeSide.get(), STDERR_FILENO) == -1)
@ -466,7 +466,7 @@ static void commonChildInit(Pipe & logPipe)
/* Reroute stdin to /dev/null. */
int fdDevNull = open(pathNullDevice.c_str(), O_RDWR);
if (fdDevNull == -1)
throw SysError(format("cannot open '%1%'") % pathNullDevice);
throw SysError("cannot open '%1%'", pathNullDevice);
if (dup2(fdDevNull, STDIN_FILENO) == -1)
throw SysError("cannot dup null device into stdin");
close(fdDevNull);
@ -488,12 +488,18 @@ void handleDiffHook(
auto diffRes = runProgram(diffHookOptions);
if (!statusOk(diffRes.first))
throw ExecError(diffRes.first, fmt("diff-hook program '%1%' %2%", diffHook, statusToString(diffRes.first)));
throw ExecError(diffRes.first,
"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());
ErrorInfo ei = error.info();
ei.hint = hintfmt("diff hook execution failed: %s",
(error.info().hint.has_value() ? error.info().hint->str() : ""));
logError(ei);
}
}
}
@ -542,37 +548,37 @@ bool UserLock::findFreeUser() {
/* Get the members of the build-users-group. */
struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str());
if (!gr)
throw Error(format("the group '%1%' specified in 'build-users-group' does not exist")
% settings.buildUsersGroup);
throw Error("the group '%1%' specified in 'build-users-group' does not exist",
settings.buildUsersGroup);
gid = gr->gr_gid;
/* Copy the result of getgrnam. */
Strings users;
for (char * * p = gr->gr_mem; *p; ++p) {
debug(format("found build user '%1%'") % *p);
debug("found build user '%1%'", *p);
users.push_back(*p);
}
if (users.empty())
throw Error(format("the build users group '%1%' has no members")
% settings.buildUsersGroup);
throw Error("the build users group '%1%' has no members",
settings.buildUsersGroup);
/* Find a user account that isn't currently in use for another
build. */
for (auto & i : users) {
debug(format("trying user '%1%'") % i);
debug("trying user '%1%'", i);
struct passwd * pw = getpwnam(i.c_str());
if (!pw)
throw Error(format("the user '%1%' in the group '%2%' does not exist")
% i % settings.buildUsersGroup);
throw Error("the user '%1%' in the group '%2%' does not exist",
i, settings.buildUsersGroup);
fnUserLock = (format("%1%/userpool/%2%") % settings.nixStateDir % pw->pw_uid).str();
AutoCloseFD fd = open(fnUserLock.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600);
if (!fd)
throw SysError(format("opening user lock '%1%'") % fnUserLock);
throw SysError("opening user lock '%1%'", fnUserLock);
if (lockFile(fd.get(), ltWrite, false)) {
fdUserLock = std::move(fd);
@ -581,8 +587,8 @@ bool UserLock::findFreeUser() {
/* Sanity check... */
if (uid == getuid() || uid == geteuid())
throw Error(format("the Nix user should not be a member of '%1%'")
% settings.buildUsersGroup);
throw Error("the Nix user should not be a member of '%1%'",
settings.buildUsersGroup);
#if __linux__
/* Get the list of supplementary groups of this build user. This
@ -592,7 +598,7 @@ bool UserLock::findFreeUser() {
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);
throw Error("failed to get list of supplementary groups for '%1%'", pw->pw_name);
supplementaryGIDs.resize(ngroups);
#endif
@ -601,6 +607,7 @@ bool UserLock::findFreeUser() {
return true;
}
}
return false;
}
@ -1151,7 +1158,10 @@ void DerivationGoal::loadDerivation()
trace("loading derivation");
if (nrFailed != 0) {
printError("cannot build missing derivation '%s'", worker.store.printStorePath(drvPath));
logError({
.name = "missing derivation during build",
.hint = hintfmt("cannot build missing derivation '%s'", worker.store.printStorePath(drvPath))
});
done(BuildResult::MiscFailure);
return;
}
@ -1302,8 +1312,12 @@ void DerivationGoal::repairClosure()
/* Check each path (slow!). */
for (auto & i : outputClosure) {
if (worker.pathContentsGood(i)) continue;
printError("found corrupted or missing path '%s' in the output closure of '%s'",
worker.store.printStorePath(i), worker.store.printStorePath(drvPath));
logError({
.name = "Corrupt path in closure",
.hint = hintfmt(
"found corrupted or missing path '%s' in the output closure of '%s'",
worker.store.printStorePath(i), worker.store.printStorePath(drvPath))
});
auto drvPath2 = outputsToDrv.find(i);
if (drvPath2 == outputsToDrv.end())
addWaitee(worker.makeSubstitutionGoal(i, Repair));
@ -1337,8 +1351,12 @@ void DerivationGoal::inputsRealised()
if (nrFailed != 0) {
if (!useDerivation)
throw Error("some dependencies of '%s' are missing", worker.store.printStorePath(drvPath));
printError("cannot build derivation '%s': %s dependencies couldn't be built",
worker.store.printStorePath(drvPath), nrFailed);
logError({
.name = "Dependencies could not be built",
.hint = hintfmt(
"cannot build derivation '%s': %s dependencies couldn't be built",
worker.store.printStorePath(drvPath), nrFailed)
});
done(BuildResult::DependencyFailed);
return;
}
@ -1523,7 +1541,7 @@ void DerivationGoal::tryLocalBuild() {
startBuilder();
} catch (BuildError & e) {
printError(e.msg());
logError(e.info());
outputLocks.unlock();
buildUser.reset();
worker.permanentFailure = true;
@ -1740,7 +1758,7 @@ void DerivationGoal::buildDone()
outputLocks.unlock();
} catch (BuildError & e) {
printError(e.msg());
logError(e.info());
outputLocks.unlock();
@ -1803,7 +1821,7 @@ HookReply DerivationGoal::tryBuildHook()
}
}
debug(format("hook reply is '%1%'") % reply);
debug("hook reply is '%1%'", reply);
if (reply == "decline")
return rpDecline;
@ -1819,8 +1837,12 @@ HookReply DerivationGoal::tryBuildHook()
} catch (SysError & e) {
if (e.errNo == EPIPE) {
printError("build hook died unexpectedly: %s",
chomp(drainFD(worker.hook->fromHook.readSide.get())));
logError({
.name = "Build hook died",
.hint = hintfmt(
"build hook died unexpectedly: %s",
chomp(drainFD(worker.hook->fromHook.readSide.get())))
});
worker.hook = 0;
return rpDecline;
} else
@ -2000,7 +2022,7 @@ void DerivationGoal::startBuilder()
string s = get(drv->env, "exportReferencesGraph").value_or("");
Strings ss = tokenizeString<Strings>(s);
if (ss.size() % 2 != 0)
throw BuildError(format("odd number of tokens in 'exportReferencesGraph': '%1%'") % s);
throw BuildError("odd number of tokens in 'exportReferencesGraph': '%1%'", s);
for (Strings::iterator i = ss.begin(); i != ss.end(); ) {
string fileName = *i++;
static std::regex regex("[A-Za-z_][A-Za-z0-9_.-]*");
@ -2049,7 +2071,7 @@ void DerivationGoal::startBuilder()
worker.store.computeFSClosure(worker.store.parseStorePath(worker.store.toStorePath(i.second.source)), closure);
} catch (InvalidPath & e) {
} catch (Error & e) {
throw Error(format("while processing 'sandbox-paths': %s") % e.what());
throw Error("while processing 'sandbox-paths': %s", e.what());
}
for (auto & i : closure) {
auto p = worker.store.printStorePath(i);
@ -2096,10 +2118,10 @@ void DerivationGoal::startBuilder()
printMsg(lvlChatty, format("setting up chroot environment in '%1%'") % chrootRootDir);
if (mkdir(chrootRootDir.c_str(), 0750) == -1)
throw SysError(format("cannot create '%1%'") % chrootRootDir);
throw SysError("cannot create '%1%'", chrootRootDir);
if (buildUser && chown(chrootRootDir.c_str(), 0, buildUser->getGID()) == -1)
throw SysError(format("cannot change ownership of '%1%'") % chrootRootDir);
throw SysError("cannot change ownership of '%1%'", chrootRootDir);
/* Create a writable /tmp in the chroot. Many builders need
this. (Of course they should really respect $TMPDIR
@ -2143,7 +2165,7 @@ void DerivationGoal::startBuilder()
chmod_(chrootStoreDir, 01775);
if (buildUser && chown(chrootStoreDir.c_str(), 0, buildUser->getGID()) == -1)
throw SysError(format("cannot change ownership of '%1%'") % chrootStoreDir);
throw SysError("cannot change ownership of '%1%'", chrootStoreDir);
for (auto & i : inputPaths) {
auto p = worker.store.printStorePath(i);
@ -2176,7 +2198,7 @@ void DerivationGoal::startBuilder()
if (needsHashRewrite()) {
if (pathExists(homeDir))
throw Error(format("home directory '%1%' exists; please remove it to assure purity of builds without sandboxing") % homeDir);
throw Error("home directory '%1%' exists; please remove it to assure purity of builds without sandboxing", homeDir);
/* We're not doing a chroot build, but we have some valid
output paths. Since we can't just overwrite or delete
@ -2221,8 +2243,7 @@ void DerivationGoal::startBuilder()
if (line == "extra-sandbox-paths" || line == "extra-chroot-dirs") {
state = stExtraChrootDirs;
} else {
throw Error(format("unknown pre-build hook command '%1%'")
% line);
throw Error("unknown pre-build hook command '%1%'", line);
}
} else if (state == stExtraChrootDirs) {
if (line == "") {
@ -2244,7 +2265,7 @@ void DerivationGoal::startBuilder()
startDaemon();
/* Run the builder. */
printMsg(lvlChatty, format("executing builder '%1%'") % drv->builder);
printMsg(lvlChatty, "executing builder '%1%'", drv->builder);
/* Create the log file. */
Path logFile = openLogFile();
@ -2982,7 +3003,7 @@ void DerivationGoal::chownToBuilder(const Path & path)
{
if (!buildUser) return;
if (chown(path.c_str(), buildUser->getUID(), buildUser->getGID()) == -1)
throw SysError(format("cannot change ownership of '%1%'") % path);
throw SysError("cannot change ownership of '%1%'", path);
}
@ -3119,7 +3140,7 @@ void DerivationGoal::runChild()
/* Bind-mount chroot directory to itself, to treat it as a
different filesystem from /, as needed for pivot_root. */
if (mount(chrootRootDir.c_str(), chrootRootDir.c_str(), 0, MS_BIND, 0) == -1)
throw SysError(format("unable to bind mount '%1%'") % chrootRootDir);
throw SysError("unable to bind mount '%1%'", chrootRootDir);
/* Bind-mount the sandbox's Nix store onto itself so that
we can mark it as a "shared" subtree, allowing bind
@ -3181,7 +3202,7 @@ void DerivationGoal::runChild()
filesystem that we want in the chroot
environment. */
auto doBind = [&](const Path & source, const Path & target, bool optional = false) {
debug(format("bind mounting '%1%' to '%2%'") % source % target);
debug("bind mounting '%1%' to '%2%'", source, target);
struct stat st;
if (stat(source.c_str(), &st) == -1) {
if (optional && errno == ENOENT)
@ -3253,16 +3274,16 @@ void DerivationGoal::runChild()
/* Do the chroot(). */
if (chdir(chrootRootDir.c_str()) == -1)
throw SysError(format("cannot change directory to '%1%'") % chrootRootDir);
throw SysError("cannot change directory to '%1%'", chrootRootDir);
if (mkdir("real-root", 0) == -1)
throw SysError("cannot create real-root directory");
if (pivot_root(".", "real-root") == -1)
throw SysError(format("cannot pivot old root directory onto '%1%'") % (chrootRootDir + "/real-root"));
throw SysError("cannot pivot old root directory onto '%1%'", (chrootRootDir + "/real-root"));
if (chroot(".") == -1)
throw SysError(format("cannot change root directory to '%1%'") % chrootRootDir);
throw SysError("cannot change root directory to '%1%'", chrootRootDir);
if (umount2("real-root", MNT_DETACH) == -1)
throw SysError("cannot unmount real root filesystem");
@ -3283,7 +3304,7 @@ void DerivationGoal::runChild()
#endif
if (chdir(tmpDirInSandbox.c_str()) == -1)
throw SysError(format("changing into '%1%'") % tmpDir);
throw SysError("changing into '%1%'", tmpDir);
/* Close all other file descriptors. */
closeMostFDs({STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO});
@ -3422,9 +3443,9 @@ void DerivationGoal::runChild()
sandboxProfile += "(allow file-read* file-write* process-exec\n";
for (auto & i : dirsInChroot) {
if (i.first != i.second.source)
throw Error(format(
"can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin")
% i.first % i.second.source);
throw Error(
"can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin",
i.first, i.second.source);
string path = i.first;
struct stat st;
@ -3515,7 +3536,7 @@ void DerivationGoal::runChild()
else if (drv->builder == "builtin:unpack-channel")
builtinUnpackChannel(drv2);
else
throw Error(format("unsupported builtin function '%1%'") % string(drv->builder, 8));
throw Error("unsupported builtin function '%1%'", string(drv->builder, 8));
_exit(0);
} catch (std::exception & e) {
writeFull(STDERR_FILENO, "error: " + string(e.what()) + "\n");
@ -3525,7 +3546,7 @@ void DerivationGoal::runChild()
execve(builder, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data());
throw SysError(format("executing '%1%'") % drv->builder);
throw SysError("executing '%1%'", drv->builder);
} catch (std::exception & e) {
writeFull(STDERR_FILENO, "\1while setting up the build environment: " + string(e.what()) + "\n");
@ -3558,7 +3579,7 @@ static void moveCheckToStore(const Path & src, const Path & dst)
directory's parent link ".."). */
struct stat st;
if (lstat(src.c_str(), &st) == -1) {
throw SysError(format("getting attributes of path '%1%'") % src);
throw SysError("getting attributes of path '%1%'", src);
}
bool changePerm = (geteuid() && S_ISDIR(st.st_mode) && !(st.st_mode & S_IWUSR));
@ -3567,7 +3588,7 @@ static void moveCheckToStore(const Path & src, const Path & dst)
chmod_(src, st.st_mode | S_IWUSR);
if (rename(src.c_str(), dst.c_str()))
throw SysError(format("renaming '%1%' to '%2%'") % src % dst);
throw SysError("renaming '%1%' to '%2%'", src, dst);
if (changePerm)
chmod_(dst, st.st_mode);
@ -3633,7 +3654,7 @@ void DerivationGoal::registerOutputs()
replaceValidPath(path, actualPath);
else
if (buildMode != bmCheck && rename(actualPath.c_str(), worker.store.toRealPath(path).c_str()) == -1)
throw SysError(format("moving build output '%1%' from the sandbox to the Nix store") % path);
throw SysError("moving build output '%1%' from the sandbox to the Nix store", path);
}
if (buildMode != bmCheck) actualPath = worker.store.toRealPath(path);
}
@ -3654,13 +3675,16 @@ void DerivationGoal::registerOutputs()
user. */
if ((!S_ISLNK(st.st_mode) && (st.st_mode & (S_IWGRP | S_IWOTH))) ||
(buildUser && st.st_uid != buildUser->getUID()))
throw BuildError(format("suspicious ownership or permission on '%1%'; rejecting this build output") % path);
throw BuildError("suspicious ownership or permission on '%1%'; rejecting this build output", path);
#endif
/* Apply hash rewriting if necessary. */
bool rewritten = false;
if (!outputRewrites.empty()) {
printError(format("warning: rewriting hashes in '%1%'; cross fingers") % path);
logWarning({
.name = "Rewriting hashes",
.hint = hintfmt("rewriting hashes in '%1%'; cross fingers", path)
});
/* Canonicalise first. This ensures that the path we're
rewriting doesn't contain a hard link to /etc/shadow or
@ -3692,8 +3716,9 @@ void DerivationGoal::registerOutputs()
/* The output path should be a regular file without execute permission. */
if (!S_ISREG(st.st_mode) || (st.st_mode & S_IXUSR) != 0)
throw BuildError(
format("output path '%1%' should be a non-executable regular file "
"since recursive hashing is not enabled (outputHashMode=flat)") % path);
"output path '%1%' should be a non-executable regular file "
"since recursive hashing is not enabled (outputHashMode=flat)",
path);
}
/* Check the hash. In hash mode, move the path produced by
@ -3823,10 +3848,10 @@ void DerivationGoal::registerOutputs()
result.isNonDeterministic = true;
Path prev = worker.store.printStorePath(i->second.path) + checkSuffix;
bool prevExists = keepPreviousRound && pathExists(prev);
auto msg = prevExists
? fmt("output '%s' of '%s' differs from '%s' from previous round",
hintformat hint = prevExists
? hintfmt("output '%s' of '%s' differs from '%s' from previous round",
worker.store.printStorePath(i->second.path), worker.store.printStorePath(drvPath), prev)
: fmt("output '%s' of '%s' differs from previous round",
: hintfmt("output '%s' of '%s' differs from previous round",
worker.store.printStorePath(i->second.path), worker.store.printStorePath(drvPath));
handleDiffHook(
@ -3836,9 +3861,14 @@ void DerivationGoal::registerOutputs()
worker.store.printStorePath(drvPath), tmpDir);
if (settings.enforceDeterminism)
throw NotDeterministic(msg);
throw NotDeterministic(hint);
logError({
.name = "Output determinism error",
.hint = hint
});
printError(msg);
curRound = nrRounds; // we know enough, bail out early
}
}
@ -4056,7 +4086,7 @@ Path DerivationGoal::openLogFile()
settings.compressLog ? ".bz2" : "");
fdLogFile = open(logFileName.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0666);
if (!fdLogFile) throw SysError(format("creating log file '%1%'") % logFileName);
if (!fdLogFile) throw SysError("creating log file '%1%'", logFileName);
logFileSink = std::make_shared<FdSink>(fdLogFile.get());
@ -4102,9 +4132,12 @@ void DerivationGoal::handleChildOutput(int fd, const string & data)
{
logSize += data.size();
if (settings.maxLogSize && logSize > settings.maxLogSize) {
printError(
format("%1% killed after writing more than %2% bytes of log output")
% getName() % settings.maxLogSize);
logError({
.name = "Max log size exceeded",
.hint = hintfmt(
"%1% killed after writing more than %2% bytes of log output",
getName(), settings.maxLogSize)
});
killChild();
done(BuildResult::LogLimitExceeded);
return;
@ -4389,7 +4422,7 @@ void SubstitutionGoal::tryNext()
throw;
} catch (Error & e) {
if (settings.tryFallback) {
printError(e.what());
logError(e.info());
tryNext();
return;
}
@ -4415,8 +4448,11 @@ void SubstitutionGoal::tryNext()
&& !sub->isTrusted
&& !info->checkSignatures(worker.store, worker.store.getPublicKeys()))
{
printError("warning: substituter '%s' does not have a valid signature for path '%s'",
sub->getUri(), worker.store.printStorePath(storePath));
logWarning({
.name = "Invalid path signature",
.hint = hintfmt("substituter '%s' does not have a valid signature for path '%s'",
sub->getUri(), worker.store.printStorePath(storePath))
});
tryNext();
return;
}
@ -4559,7 +4595,6 @@ void SubstitutionGoal::handleEOF(int fd)
if (fd == outPipe.readSide.get()) worker.wakeUp(shared_from_this());
}
//////////////////////////////////////////////////////////////////////
@ -4776,9 +4811,9 @@ void Worker::run(const Goals & _topGoals)
if (!children.empty() || !waitingForAWhile.empty())
waitForInput();
else {
if (awake.empty() && 0 == settings.maxBuildJobs) throw Error(
"unable to start any build; either increase '--max-jobs' "
"or enable remote builds");
if (awake.empty() && 0 == settings.maxBuildJobs)
throw Error("unable to start any build; either increase '--max-jobs' "
"or enable remote builds");
assert(!awake.empty());
}
}
@ -4791,7 +4826,6 @@ void Worker::run(const Goals & _topGoals)
assert(!settings.keepGoing || children.empty());
}
void Worker::waitForInput()
{
printMsg(lvlVomit, "waiting for children");
@ -4830,7 +4864,7 @@ void Worker::waitForInput()
if (!waitingForAWhile.empty()) {
useTimeout = true;
if (lastWokenUp == steady_time_point::min())
printError("waiting for locks, build slots or build users...");
printInfo("waiting for locks, build slots or build users...");
if (lastWokenUp == steady_time_point::min() || lastWokenUp > before) lastWokenUp = before;
timeout = std::max(1L,
(long) std::chrono::duration_cast<std::chrono::seconds>(
@ -4879,15 +4913,15 @@ void Worker::waitForInput()
// FIXME: is there a cleaner way to handle pt close
// than EIO? Is this even standard?
if (rd == 0 || (rd == -1 && errno == EIO)) {
debug(format("%1%: got EOF") % goal->getName());
debug("%1%: got EOF", goal->getName());
goal->handleEOF(k);
j->fds.erase(k);
} else if (rd == -1) {
if (errno != EINTR)
throw SysError("%s: read failed", goal->getName());
} else {
printMsg(lvlVomit, format("%1%: read %2% bytes")
% goal->getName() % rd);
printMsg(lvlVomit, "%1%: read %2% bytes",
goal->getName(), rd);
string data((char *) buffer.data(), rd);
j->lastOutput = after;
goal->handleChildOutput(k, data);
@ -4900,9 +4934,12 @@ void Worker::waitForInput()
j->respectTimeouts &&
after - j->lastOutput >= std::chrono::seconds(settings.maxSilentTime))
{
printError(
format("%1% timed out after %2% seconds of silence")
% goal->getName() % settings.maxSilentTime);
logError({
.name = "Silent build timeout",
.hint = hintfmt(
"%1% timed out after %2% seconds of silence",
goal->getName(), settings.maxSilentTime)
});
goal->timedOut();
}
@ -4911,9 +4948,12 @@ void Worker::waitForInput()
j->respectTimeouts &&
after - j->timeStarted >= std::chrono::seconds(settings.buildTimeout))
{
printError(
format("%1% timed out after %2% seconds")
% goal->getName() % settings.buildTimeout);
logError({
.name = "Build timeout",
.hint = hintfmt(
"%1% timed out after %2% seconds",
goal->getName(), settings.buildTimeout)
});
goal->timedOut();
}
}
@ -4972,7 +5012,11 @@ bool Worker::pathContentsGood(const StorePath & path)
res = info->narHash == nullHash || info->narHash == current.first;
}
pathContentsGoodCache.insert_or_assign(path.clone(), res);
if (!res) printError("path '%s' is corrupted or missing!", store.printStorePath(path));
if (!res)
logError({
.name = "Corrupted path",
.hint = hintfmt("path '%s' is corrupted or missing!", store.printStorePath(path))
});
return res;
}
@ -5028,7 +5072,6 @@ void LocalStore::buildPaths(const std::vector<StorePathWithOutputs> & drvPaths,
throw Error(worker.exitStatus(), "build of %s failed", showPaths(failed));
}
BuildResult LocalStore::buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
BuildMode buildMode)
{

View file

@ -22,7 +22,11 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir,
srcFiles = readDirectory(srcDir);
} catch (SysError & e) {
if (e.errNo == ENOTDIR) {
printError("warning: not including '%s' in the user environment because it's not a directory", srcDir);
logWarning(
ErrorInfo {
.name = "Create links - directory",
.hint = hintfmt("not including '%s' in the user environment because it's not a directory", srcDir)
});
return;
}
throw;
@ -41,7 +45,11 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir,
throw SysError("getting status of '%1%'", srcFile);
} catch (SysError & e) {
if (e.errNo == ENOENT || e.errNo == ENOTDIR) {
printError("warning: skipping dangling symlink '%s'", dstFile);
logWarning(
ErrorInfo {
.name = "Create links - skipping symlink",
.hint = hintfmt("skipping dangling symlink '%s'", dstFile)
});
continue;
}
throw;
@ -72,15 +80,15 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir,
if (!S_ISDIR(lstat(target).st_mode))
throw Error("collision between '%1%' and non-directory '%2%'", srcFile, target);
if (unlink(dstFile.c_str()) == -1)
throw SysError(format("unlinking '%1%'") % dstFile);
throw SysError("unlinking '%1%'", dstFile);
if (mkdir(dstFile.c_str(), 0755) == -1)
throw SysError(format("creating directory '%1%'"));
throw SysError("creating directory '%1%'", dstFile);
createLinks(state, target, dstFile, state.priorities[dstFile]);
createLinks(state, srcFile, dstFile, priority);
continue;
}
} else if (errno != ENOENT)
throw SysError(format("getting status of '%1%'") % dstFile);
throw SysError("getting status of '%1%'", dstFile);
}
else {
@ -99,11 +107,11 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir,
if (prevPriority < priority)
continue;
if (unlink(dstFile.c_str()) == -1)
throw SysError(format("unlinking '%1%'") % dstFile);
throw SysError("unlinking '%1%'", dstFile);
} else if (S_ISDIR(dstSt.st_mode))
throw Error("collision between non-directory '%1%' and directory '%2%'", srcFile, dstFile);
} else if (errno != ENOENT)
throw SysError(format("getting status of '%1%'") % dstFile);
throw SysError("getting status of '%1%'", dstFile);
}
createSymlink(srcFile, dstFile);

View file

@ -18,7 +18,7 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData)
auto getAttr = [&](const string & name) {
auto i = drv.env.find(name);
if (i == drv.env.end()) throw Error(format("attribute '%s' missing") % name);
if (i == drv.env.end()) throw Error("attribute '%s' missing", name);
return i->second;
};
@ -54,7 +54,7 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData)
auto executable = drv.env.find("executable");
if (executable != drv.env.end() && executable->second == "1") {
if (chmod(storePath.c_str(), 0755) == -1)
throw SysError(format("making '%1%' executable") % storePath);
throw SysError("making '%1%' executable", storePath);
}
};

View file

@ -73,6 +73,18 @@ struct TunnelLogger : public Logger
enqueueMsg(*buf.s);
}
void logEI(const ErrorInfo & ei) override
{
if (ei.level > verbosity) return;
std::stringstream oss;
oss << ei;
StringSink buf;
buf << STDERR_NEXT << oss.str() << "\n"; // (fs.s + "\n");
enqueueMsg(*buf.s);
}
/* startWork() means that we're starting an operation for which we
want to send out stderr to the client. */
void startWork()
@ -744,7 +756,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
}
default:
throw Error(format("invalid operation %1%") % op);
throw Error("invalid operation %1%", op);
}
}

View file

@ -87,7 +87,7 @@ static void expect(std::istream & str, const string & s)
char s2[s.size()];
str.read(s2, s.size());
if (string(s2, s.size()) != s)
throw FormatError(format("expected string '%1%'") % s);
throw FormatError("expected string '%1%'", s);
}
@ -114,7 +114,7 @@ static Path parsePath(std::istream & str)
{
string s = parseString(str);
if (s.size() == 0 || s[0] != '/')
throw FormatError(format("bad path '%1%' in derivation") % s);
throw FormatError("bad path '%1%' in derivation", s);
return s;
}
@ -196,7 +196,7 @@ Derivation readDerivation(const Store & store, const Path & drvPath)
try {
return parseDerivation(store, readFile(drvPath));
} catch (FormatError & e) {
throw Error(format("error parsing derivation '%1%': %2%") % drvPath % e.msg());
throw Error("error parsing derivation '%1%': %2%", drvPath, e.msg());
}
}

View file

@ -112,7 +112,7 @@ struct curlFileTransfer : public FileTransfer
if (requestHeaders) curl_slist_free_all(requestHeaders);
try {
if (!done)
fail(FileTransferError(Interrupted, format("download of '%s' was interrupted") % request.uri));
fail(FileTransferError(Interrupted, "download of '%s' was interrupted", request.uri));
} catch (...) {
ignoreException();
}
@ -517,7 +517,7 @@ struct curlFileTransfer : public FileTransfer
int running;
CURLMcode mc = curl_multi_perform(curlm, &running);
if (mc != CURLM_OK)
throw nix::Error(format("unexpected error from curl_multi_perform(): %s") % curl_multi_strerror(mc));
throw nix::Error("unexpected error from curl_multi_perform(): %s", curl_multi_strerror(mc));
/* Set the promises of any finished requests. */
CURLMsg * msg;
@ -547,7 +547,7 @@ struct curlFileTransfer : public FileTransfer
vomit("download thread waiting for %d ms", sleepTimeMs);
mc = curl_multi_wait(curlm, extraFDs, 1, sleepTimeMs, &numfds);
if (mc != CURLM_OK)
throw nix::Error(format("unexpected error from curl_multi_wait(): %s") % curl_multi_strerror(mc));
throw nix::Error("unexpected error from curl_multi_wait(): %s", curl_multi_strerror(mc));
nextWakeup = std::chrono::steady_clock::time_point();
@ -599,7 +599,11 @@ struct curlFileTransfer : public FileTransfer
workerThreadMain();
} catch (nix::Interrupted & e) {
} catch (std::exception & e) {
printError("unexpected error in download thread: %s", e.what());
logError({
.name = "File transfer",
.hint = hintfmt("unexpected error in download thread: %s",
e.what())
});
}
{

View file

@ -103,8 +103,9 @@ class FileTransferError : public Error
{
public:
FileTransfer::Error error;
FileTransferError(FileTransfer::Error error, const FormatOrString & fs)
: Error(fs), error(error)
template<typename... Args>
FileTransferError(FileTransfer::Error error, const Args & ... args)
: Error(args...), error(error)
{ }
};

View file

@ -38,10 +38,10 @@ AutoCloseFD LocalStore::openGCLock(LockType lockType)
AutoCloseFD fdGCLock = open(fnGCLock.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600);
if (!fdGCLock)
throw SysError(format("opening global GC lock '%1%'") % fnGCLock);
throw SysError("opening global GC lock '%1%'", fnGCLock);
if (!lockFile(fdGCLock.get(), lockType, false)) {
printError(format("waiting for the big garbage collector lock..."));
printInfo("waiting for the big garbage collector lock...");
lockFile(fdGCLock.get(), lockType, true);
}
@ -65,8 +65,8 @@ static void makeSymlink(const Path & link, const Path & target)
/* Atomically replace the old one. */
if (rename(tempLink.c_str(), link.c_str()) == -1)
throw SysError(format("cannot rename '%1%' to '%2%'")
% tempLink % link);
throw SysError("cannot rename '%1%' to '%2%'",
tempLink , link);
}
@ -91,15 +91,15 @@ Path LocalFSStore::addPermRoot(const StorePath & storePath,
Path gcRoot(canonPath(_gcRoot));
if (isInStore(gcRoot))
throw Error(format(
throw Error(
"creating a garbage collector root (%1%) in the Nix store is forbidden "
"(are you running nix-build inside the store?)") % gcRoot);
"(are you running nix-build inside the store?)", gcRoot);
if (indirect) {
/* Don't clobber the link if it already exists and doesn't
point to the Nix store. */
if (pathExists(gcRoot) && (!isLink(gcRoot) || !isInStore(readLink(gcRoot))))
throw Error(format("cannot create symlink '%1%'; already exists") % gcRoot);
throw Error("cannot create symlink '%1%'; already exists", gcRoot);
makeSymlink(gcRoot, printStorePath(storePath));
addIndirectRoot(gcRoot);
}
@ -109,10 +109,10 @@ Path LocalFSStore::addPermRoot(const StorePath & storePath,
Path rootsDir = canonPath((format("%1%/%2%") % stateDir % gcRootsDir).str());
if (string(gcRoot, 0, rootsDir.size() + 1) != rootsDir + "/")
throw Error(format(
throw Error(
"path '%1%' is not a valid garbage collector root; "
"it's not in the directory '%2%'")
% gcRoot % rootsDir);
"it's not in the directory '%2%'",
gcRoot, rootsDir);
}
if (baseNameOf(gcRoot) == std::string(storePath.to_string()))
@ -129,10 +129,13 @@ Path LocalFSStore::addPermRoot(const StorePath & storePath,
if (settings.checkRootReachability) {
auto roots = findRoots(false);
if (roots[storePath.clone()].count(gcRoot) == 0)
printError(
"warning: '%1%' is not in a directory where the garbage collector looks for roots; "
logWarning(
ErrorInfo {
.name = "GC root",
.hint = hintfmt("warning: '%1%' is not in a directory where the garbage collector looks for roots; "
"therefore, '%2%' might be removed by the garbage collector",
gcRoot, printStorePath(storePath));
gcRoot, printStorePath(storePath))
});
}
/* Grab the global GC root, causing us to block while a GC is in
@ -170,7 +173,7 @@ void LocalStore::addTempRoot(const StorePath & path)
way. */
struct stat st;
if (fstat(state->fdTempRoots.get(), &st) == -1)
throw SysError(format("statting '%1%'") % fnTempRoots);
throw SysError("statting '%1%'", fnTempRoots);
if (st.st_size == 0) break;
/* The garbage collector deleted this file before we could
@ -216,7 +219,7 @@ void LocalStore::findTempRoots(FDs & fds, Roots & tempRoots, bool censor)
if (!*fd) {
/* It's okay if the file has disappeared. */
if (errno == ENOENT) continue;
throw SysError(format("opening temporary roots file '%1%'") % path);
throw SysError("opening temporary roots file '%1%'", path);
}
/* This should work, but doesn't, for some reason. */
@ -227,7 +230,7 @@ void LocalStore::findTempRoots(FDs & fds, Roots & tempRoots, bool censor)
only succeed if the owning process has died. In that case
we don't care about its temporary roots. */
if (lockFile(fd->get(), ltWrite, false)) {
printError(format("removing stale temporary roots file '%1%'") % path);
printInfo("removing stale temporary roots file '%1%'", path);
unlink(path.c_str());
writeFull(fd->get(), "d");
continue;
@ -403,7 +406,7 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
if (!fdDir) {
if (errno == ENOENT || errno == EACCES)
continue;
throw SysError(format("opening %1%") % fdStr);
throw SysError("opening %1%", fdStr);
}
struct dirent * fd_ent;
while (errno = 0, fd_ent = readdir(fdDir.get())) {
@ -413,7 +416,7 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
if (errno) {
if (errno == ESRCH)
continue;
throw SysError(format("iterating /proc/%1%/fd") % ent->d_name);
throw SysError("iterating /proc/%1%/fd", ent->d_name);
}
fdDir.reset();
@ -541,7 +544,7 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path)
struct stat st;
if (lstat(realPath.c_str(), &st)) {
if (errno == ENOENT) return;
throw SysError(format("getting status of %1%") % realPath);
throw SysError("getting status of %1%", realPath);
}
printInfo(format("deleting '%1%'") % path);
@ -559,10 +562,10 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path)
// size.
try {
if (chmod(realPath.c_str(), st.st_mode | S_IWUSR) == -1)
throw SysError(format("making '%1%' writable") % realPath);
throw SysError("making '%1%' writable", realPath);
Path tmp = trashDir + "/" + std::string(baseNameOf(path));
if (rename(realPath.c_str(), tmp.c_str()))
throw SysError(format("unable to rename '%1%' to '%2%'") % realPath % tmp);
throw SysError("unable to rename '%1%' to '%2%'", realPath, tmp);
state.bytesInvalidated += size;
} catch (SysError & e) {
if (e.errNo == ENOSPC) {
@ -681,7 +684,7 @@ void LocalStore::tryToDelete(GCState & state, const Path & path)
void LocalStore::removeUnusedLinks(const GCState & state)
{
AutoCloseDir dir(opendir(linksDir.c_str()));
if (!dir) throw SysError(format("opening directory '%1%'") % linksDir);
if (!dir) throw SysError("opening directory '%1%'", linksDir);
long long actualSize = 0, unsharedSize = 0;
@ -694,7 +697,7 @@ void LocalStore::removeUnusedLinks(const GCState & state)
struct stat st;
if (lstat(path.c_str(), &st) == -1)
throw SysError(format("statting '%1%'") % path);
throw SysError("statting '%1%'", path);
if (st.st_nlink != 1) {
actualSize += st.st_size;
@ -705,14 +708,14 @@ void LocalStore::removeUnusedLinks(const GCState & state)
printMsg(lvlTalkative, format("deleting unused link '%1%'") % path);
if (unlink(path.c_str()) == -1)
throw SysError(format("deleting '%1%'") % path);
throw SysError("deleting '%1%'", path);
state.results.bytesFreed += st.st_size;
}
struct stat st;
if (stat(linksDir.c_str(), &st) == -1)
throw SysError(format("statting '%1%'") % linksDir);
throw SysError("statting '%1%'", linksDir);
long long overhead = st.st_blocks * 512ULL;
printInfo(format("note: currently hard linking saves %.2f MiB")
@ -747,7 +750,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
/* Find the roots. Since we've grabbed the GC lock, the set of
permanent roots cannot increase now. */
printError("finding garbage collector roots...");
printInfo("finding garbage collector roots...");
Roots rootMap;
if (!options.ignoreLiveness)
findRootsNoTemp(rootMap, true);
@ -799,14 +802,14 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
} else if (options.maxFreed > 0) {
if (state.shouldDelete)
printError("deleting garbage...");
printInfo("deleting garbage...");
else
printError("determining live/dead paths...");
printInfo("determining live/dead paths...");
try {
AutoCloseDir dir(opendir(realStoreDir.c_str()));
if (!dir) throw SysError(format("opening directory '%1%'") % realStoreDir);
if (!dir) throw SysError("opening directory '%1%'", realStoreDir);
/* Read the store and immediately delete all paths that
aren't valid. When using --max-freed etc., deleting
@ -868,7 +871,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
/* Clean up the links directory. */
if (options.action == GCOptions::gcDeleteDead || options.action == GCOptions::gcDeleteSpecific) {
printError("deleting unused links...");
printInfo("deleting unused links...");
removeUnusedLinks(state);
}

View file

@ -74,7 +74,7 @@ static void atomicWrite(const Path & path, const std::string & s)
AutoDelete del(tmp, false);
writeFile(tmp, s);
if (rename(tmp.c_str(), path.c_str()))
throw SysError(format("renaming '%1%' to '%2%'") % tmp % path);
throw SysError("renaming '%1%' to '%2%'", tmp, path);
del.cancel();
}

View file

@ -22,7 +22,7 @@ struct LocalStoreAccessor : public FSAccessor
{
Path storePath = store->toStorePath(path);
if (!store->isValidPath(store->parseStorePath(storePath)))
throw InvalidPath(format("path '%1%' is not a valid store path") % storePath);
throw InvalidPath("path '%1%' is not a valid store path", storePath);
return store->getRealStoreDir() + std::string(path, store->storeDir.size());
}
@ -33,11 +33,11 @@ struct LocalStoreAccessor : public FSAccessor
struct stat st;
if (lstat(realPath.c_str(), &st)) {
if (errno == ENOENT || errno == ENOTDIR) return {Type::tMissing, 0, false};
throw SysError(format("getting status of '%1%'") % path);
throw SysError("getting status of '%1%'", path);
}
if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode))
throw Error(format("file '%1%' has unsupported type") % path);
throw Error("file '%1%' has unsupported type", path);
return {
S_ISREG(st.st_mode) ? Type::tRegular :

View file

@ -87,18 +87,22 @@ LocalStore::LocalStore(const Params & params)
struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str());
if (!gr)
printError(format("warning: the group '%1%' specified in 'build-users-group' does not exist")
% settings.buildUsersGroup);
logError({
.name = "'build-users-group' not found",
.hint = hintfmt(
"warning: the group '%1%' specified in 'build-users-group' does not exist",
settings.buildUsersGroup)
});
else {
struct stat st;
if (stat(realStoreDir.c_str(), &st))
throw SysError(format("getting attributes of path '%1%'") % realStoreDir);
throw SysError("getting attributes of path '%1%'", realStoreDir);
if (st.st_uid != 0 || st.st_gid != gr->gr_gid || (st.st_mode & ~S_IFMT) != perm) {
if (chown(realStoreDir.c_str(), 0, gr->gr_gid) == -1)
throw SysError(format("changing ownership of path '%1%'") % realStoreDir);
throw SysError("changing ownership of path '%1%'", realStoreDir);
if (chmod(realStoreDir.c_str(), perm) == -1)
throw SysError(format("changing permissions on path '%1%'") % realStoreDir);
throw SysError("changing permissions on path '%1%'", realStoreDir);
}
}
}
@ -109,12 +113,12 @@ LocalStore::LocalStore(const Params & params)
struct stat st;
while (path != "/") {
if (lstat(path.c_str(), &st))
throw SysError(format("getting status of '%1%'") % path);
throw SysError("getting status of '%1%'", path);
if (S_ISLNK(st.st_mode))
throw Error(format(
throw Error(
"the path '%1%' is a symlink; "
"this is not allowed for the Nix store and its parent directories")
% path);
"this is not allowed for the Nix store and its parent directories",
path);
path = dirOf(path);
}
}
@ -147,7 +151,7 @@ LocalStore::LocalStore(const Params & params)
globalLock = openLockFile(globalLockPath.c_str(), true);
if (!lockFile(globalLock.get(), ltRead, false)) {
printError("waiting for the big Nix store lock...");
printInfo("waiting for the big Nix store lock...");
lockFile(globalLock.get(), ltRead, true);
}
@ -155,8 +159,8 @@ LocalStore::LocalStore(const Params & params)
upgrade. */
int curSchema = getSchema();
if (curSchema > nixSchemaVersion)
throw Error(format("current Nix store schema is version %1%, but I only support %2%")
% curSchema % nixSchemaVersion);
throw Error("current Nix store schema is version %1%, but I only support %2%",
curSchema, nixSchemaVersion);
else if (curSchema == 0) { /* new store */
curSchema = nixSchemaVersion;
@ -178,7 +182,7 @@ LocalStore::LocalStore(const Params & params)
"please upgrade Nix to version 1.11 first.");
if (!lockFile(globalLock.get(), ltWrite, false)) {
printError("waiting for exclusive access to the Nix store...");
printInfo("waiting for exclusive access to the Nix store...");
lockFile(globalLock.get(), ltWrite, true);
}
@ -256,7 +260,7 @@ LocalStore::~LocalStore()
}
if (future.valid()) {
printError("waiting for auto-GC to finish on exit...");
printInfo("waiting for auto-GC to finish on exit...");
future.get();
}
@ -284,7 +288,7 @@ int LocalStore::getSchema()
if (pathExists(schemaPath)) {
string s = readFile(schemaPath);
if (!string2Int(s, curSchema))
throw Error(format("'%1%' is corrupt") % schemaPath);
throw Error("'%1%' is corrupt", schemaPath);
}
return curSchema;
}
@ -293,7 +297,7 @@ int LocalStore::getSchema()
void LocalStore::openDB(State & state, bool create)
{
if (access(dbDir.c_str(), R_OK | W_OK))
throw SysError(format("Nix database directory '%1%' is not writable") % dbDir);
throw SysError("Nix database directory '%1%' is not writable", dbDir);
/* Open the Nix database. */
string dbPath = dbDir + "/db.sqlite";
@ -367,7 +371,7 @@ void LocalStore::makeStoreWritable()
throw SysError("setting up a private mount namespace");
if (mount(0, realStoreDir.c_str(), "none", MS_REMOUNT | MS_BIND, 0) == -1)
throw SysError(format("remounting %1% writable") % realStoreDir);
throw SysError("remounting %1% writable", realStoreDir);
}
#endif
}
@ -388,7 +392,7 @@ static void canonicaliseTimestampAndPermissions(const Path & path, const struct
| 0444
| (st.st_mode & S_IXUSR ? 0111 : 0);
if (chmod(path.c_str(), mode) == -1)
throw SysError(format("changing mode of '%1%' to %2$o") % path % mode);
throw SysError("changing mode of '%1%' to %2$o", path, mode);
}
}
@ -406,7 +410,7 @@ static void canonicaliseTimestampAndPermissions(const Path & path, const struct
#else
if (!S_ISLNK(st.st_mode) && utimes(path.c_str(), times) == -1)
#endif
throw SysError(format("changing modification time of '%1%'") % path);
throw SysError("changing modification time of '%1%'", path);
}
}
@ -415,7 +419,7 @@ void canonicaliseTimestampAndPermissions(const Path & path)
{
struct stat st;
if (lstat(path.c_str(), &st))
throw SysError(format("getting attributes of path '%1%'") % path);
throw SysError("getting attributes of path '%1%'", path);
canonicaliseTimestampAndPermissions(path, st);
}
@ -430,17 +434,17 @@ static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSe
setattrlist() to remove other attributes as well. */
if (lchflags(path.c_str(), 0)) {
if (errno != ENOTSUP)
throw SysError(format("clearing flags of path '%1%'") % path);
throw SysError("clearing flags of path '%1%'", path);
}
#endif
struct stat st;
if (lstat(path.c_str(), &st))
throw SysError(format("getting attributes of path '%1%'") % path);
throw SysError("getting attributes of path '%1%'", path);
/* Really make sure that the path is of a supported type. */
if (!(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode)))
throw Error(format("file '%1%' has an unsupported type") % path);
throw Error("file '%1%' has an unsupported type", path);
#if __linux__
/* Remove extended attributes / ACLs. */
@ -474,7 +478,7 @@ static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSe
if (fromUid != (uid_t) -1 && st.st_uid != fromUid) {
assert(!S_ISDIR(st.st_mode));
if (inodesSeen.find(Inode(st.st_dev, st.st_ino)) == inodesSeen.end())
throw BuildError(format("invalid ownership on file '%1%'") % path);
throw BuildError("invalid ownership on file '%1%'", path);
mode_t mode = st.st_mode & ~S_IFMT;
assert(S_ISLNK(st.st_mode) || (st.st_uid == geteuid() && (mode == 0444 || mode == 0555) && st.st_mtime == mtimeStore));
return;
@ -498,8 +502,8 @@ static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSe
if (!S_ISLNK(st.st_mode) &&
chown(path.c_str(), geteuid(), getegid()) == -1)
#endif
throw SysError(format("changing owner of '%1%' to %2%")
% path % geteuid());
throw SysError("changing owner of '%1%' to %2%",
path, geteuid());
}
if (S_ISDIR(st.st_mode)) {
@ -518,11 +522,11 @@ void canonicalisePathMetaData(const Path & path, uid_t fromUid, InodesSeen & ino
be a symlink, since we can't change its ownership. */
struct stat st;
if (lstat(path.c_str(), &st))
throw SysError(format("getting attributes of path '%1%'") % path);
throw SysError("getting attributes of path '%1%'", path);
if (st.st_uid != geteuid()) {
assert(S_ISLNK(st.st_mode));
throw Error(format("wrong ownership of top-level store path '%1%'") % path);
throw Error("wrong ownership of top-level store path '%1%'", path);
}
}
@ -859,7 +863,7 @@ void LocalStore::querySubstitutablePathInfos(const StorePathSet & paths,
} catch (SubstituterDisabled &) {
} catch (Error & e) {
if (settings.tryFallback)
printError(e.what());
logError(e.info());
else
throw;
}
@ -1187,7 +1191,7 @@ void LocalStore::invalidatePathChecked(const StorePath & path)
bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
{
printError(format("reading the Nix store..."));
printInfo(format("reading the Nix store..."));
bool errors = false;
@ -1219,12 +1223,15 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
Path linkPath = linksDir + "/" + link.name;
string hash = hashPath(htSHA256, linkPath).first.to_string(Base32, false);
if (hash != link.name) {
printError(
"link '%s' was modified! expected hash '%s', got '%s'",
linkPath, link.name, hash);
logError({
.name = "Invalid hash",
.hint = hintfmt(
"link '%s' was modified! expected hash '%s', got '%s'",
linkPath, link.name, hash)
});
if (repair) {
if (unlink(linkPath.c_str()) == 0)
printError("removed link '%s'", linkPath);
printInfo("removed link '%s'", linkPath);
else
throw SysError("removing corrupt link '%s'", linkPath);
} else {
@ -1254,8 +1261,11 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
auto current = hashSink->finish();
if (info->narHash != nullHash && info->narHash != current.first) {
printError("path '%s' was modified! expected hash '%s', got '%s'",
printStorePath(i), info->narHash.to_string(Base32, true), current.first.to_string(Base32, true));
logError({
.name = "Invalid hash - path modified",
.hint = hintfmt("path '%s' was modified! expected hash '%s', got '%s'",
printStorePath(i), info->narHash.to_string(Base32, true), current.first.to_string(Base32, true))
});
if (repair) repairPath(i); else errors = true;
} else {
@ -1263,14 +1273,14 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
/* Fill in missing hashes. */
if (info->narHash == nullHash) {
printError("fixing missing hash on '%s'", printStorePath(i));
printInfo("fixing missing hash on '%s'", printStorePath(i));
info->narHash = current.first;
update = true;
}
/* Fill in missing narSize fields (from old stores). */
if (info->narSize == 0) {
printError("updating size field on '%s' to %s", printStorePath(i), current.second);
printInfo("updating size field on '%s' to %s", printStorePath(i), current.second);
info->narSize = current.second;
update = true;
}
@ -1286,7 +1296,7 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
/* It's possible that the path got GC'ed, so ignore
errors on invalid paths. */
if (isValidPath(i))
printError("error: %s", e.msg());
logError(e.info());
else
warn(e.msg());
errors = true;
@ -1306,7 +1316,10 @@ void LocalStore::verifyPath(const Path & pathS, const StringSet & store,
if (!done.insert(pathS).second) return;
if (!isStorePath(pathS)) {
printError("path '%s' is not in the Nix store", pathS);
logError({
.name = "Nix path not found",
.hint = hintfmt("path '%s' is not in the Nix store", pathS)
});
return;
}
@ -1325,16 +1338,19 @@ void LocalStore::verifyPath(const Path & pathS, const StringSet & store,
}
if (canInvalidate) {
printError("path '%s' disappeared, removing from database...", pathS);
printInfo("path '%s' disappeared, removing from database...", pathS);
auto state(_state.lock());
invalidatePath(*state, path);
} else {
printError("path '%s' disappeared, but it still has valid referrers!", pathS);
logError({
.name = "Missing path with referrers",
.hint = hintfmt("path '%s' disappeared, but it still has valid referrers!", pathS)
});
if (repair)
try {
repairPath(path);
} catch (Error & e) {
warn(e.msg());
logWarning(e.info());
errors = true;
}
else errors = true;
@ -1374,7 +1390,7 @@ static void makeMutable(const Path & path)
AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
if (fd == -1) {
if (errno == ELOOP) return; // it's a symlink
throw SysError(format("opening file '%1%'") % path);
throw SysError("opening file '%1%'", path);
}
unsigned int flags = 0, old;
@ -1392,7 +1408,7 @@ static void makeMutable(const Path & path)
void LocalStore::upgradeStore7()
{
if (getuid() != 0) return;
printError("removing immutable bits from the Nix store (this may take a while)...");
printInfo("removing immutable bits from the Nix store (this may take a while)...");
makeMutable(realStoreDir);
}

View file

@ -184,7 +184,7 @@ struct NarAccessor : public FSAccessor
auto i = get(path);
if (i.type != FSAccessor::Type::tDirectory)
throw Error(format("path '%1%' inside NAR file is not a directory") % path);
throw Error("path '%1%' inside NAR file is not a directory", path);
StringSet res;
for (auto & child : i.children)
@ -197,7 +197,7 @@ struct NarAccessor : public FSAccessor
{
auto i = get(path);
if (i.type != FSAccessor::Type::tRegular)
throw Error(format("path '%1%' inside NAR file is not a regular file") % path);
throw Error("path '%1%' inside NAR file is not a regular file", path);
if (getNarBytes) return getNarBytes(i.start, i.size);
@ -209,7 +209,7 @@ struct NarAccessor : public FSAccessor
{
auto i = get(path);
if (i.type != FSAccessor::Type::tSymlink)
throw Error(format("path '%1%' inside NAR file is not a symlink") % path);
throw Error("path '%1%' inside NAR file is not a symlink", path);
return i.target;
}
};

View file

@ -7,7 +7,7 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
: ValidPathInfo(StorePath::dummy.clone()) // FIXME: hack
{
auto corrupt = [&]() {
throw Error(format("NAR info file '%1%' is corrupt") % whence);
throw Error("NAR info file '%1%' is corrupt", whence);
};
auto parseHashField = [&](const string & s) {

View file

@ -19,9 +19,9 @@ static void makeWritable(const Path & path)
{
struct stat st;
if (lstat(path.c_str(), &st))
throw SysError(format("getting attributes of path '%1%'") % path);
throw SysError("getting attributes of path '%1%'", path);
if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1)
throw SysError(format("changing writability of '%1%'") % path);
throw SysError("changing writability of '%1%'", path);
}
@ -47,7 +47,7 @@ LocalStore::InodeHash LocalStore::loadInodeHash()
InodeHash inodeHash;
AutoCloseDir dir(opendir(linksDir.c_str()));
if (!dir) throw SysError(format("opening directory '%1%'") % linksDir);
if (!dir) throw SysError("opening directory '%1%'", linksDir);
struct dirent * dirent;
while (errno = 0, dirent = readdir(dir.get())) { /* sic */
@ -55,7 +55,7 @@ LocalStore::InodeHash LocalStore::loadInodeHash()
// We don't care if we hit non-hash files, anything goes
inodeHash.insert(dirent->d_ino);
}
if (errno) throw SysError(format("reading directory '%1%'") % linksDir);
if (errno) throw SysError("reading directory '%1%'", linksDir);
printMsg(lvlTalkative, format("loaded %1% hash inodes") % inodeHash.size());
@ -68,7 +68,7 @@ Strings LocalStore::readDirectoryIgnoringInodes(const Path & path, const InodeHa
Strings names;
AutoCloseDir dir(opendir(path.c_str()));
if (!dir) throw SysError(format("opening directory '%1%'") % path);
if (!dir) throw SysError("opening directory '%1%'", path);
struct dirent * dirent;
while (errno = 0, dirent = readdir(dir.get())) { /* sic */
@ -83,7 +83,7 @@ Strings LocalStore::readDirectoryIgnoringInodes(const Path & path, const InodeHa
if (name == "." || name == "..") continue;
names.push_back(name);
}
if (errno) throw SysError(format("reading directory '%1%'") % path);
if (errno) throw SysError("reading directory '%1%'", path);
return names;
}
@ -96,7 +96,7 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
struct stat st;
if (lstat(path.c_str(), &st))
throw SysError(format("getting attributes of path '%1%'") % path);
throw SysError("getting attributes of path '%1%'", path);
#if __APPLE__
/* HFS/macOS has some undocumented security feature disabling hardlinking for
@ -130,7 +130,10 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
NixOS (example: $fontconfig/var/cache being modified). Skip
those files. FIXME: check the modification time. */
if (S_ISREG(st.st_mode) && (st.st_mode & S_IWUSR)) {
printError(format("skipping suspicious writable file '%1%'") % path);
logWarning({
.name = "Suspicious file",
.hint = hintfmt("skipping suspicious writable file '%1%'", path)
});
return;
}
@ -186,7 +189,7 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
current file with a hard link to that file. */
struct stat stLink;
if (lstat(linkPath.c_str(), &stLink))
throw SysError(format("getting attributes of path '%1%'") % linkPath);
throw SysError("getting attributes of path '%1%'", linkPath);
if (st.st_ino == stLink.st_ino) {
debug(format("'%1%' is already linked to '%2%'") % path % linkPath);
@ -194,7 +197,10 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
}
if (st.st_size != stLink.st_size) {
printError(format("removing corrupted link '%1%'") % linkPath);
logWarning({
.name = "Corrupted link",
.hint = hintfmt("removing corrupted link '%1%'", linkPath)
});
unlink(linkPath.c_str());
goto retry;
}
@ -229,7 +235,10 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
/* Atomically replace the old file with the new hard link. */
if (rename(tempLink.c_str(), path.c_str()) == -1) {
if (unlink(tempLink.c_str()) == -1)
printError(format("unable to unlink '%1%'") % tempLink);
logError({
.name = "Unlink error",
.hint = hintfmt("unable to unlink '%1%'", tempLink)
});
if (errno == EMLINK) {
/* Some filesystems generate too many links on the rename,
rather than on the original link. (Probably it
@ -238,7 +247,7 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
debug("'%s' has reached maximum number of links", linkPath);
return;
}
throw SysError(format("cannot rename '%1%' to '%2%'") % tempLink % path);
throw SysError("cannot rename '%1%' to '%2%'", tempLink, path);
}
stats.filesLinked++;

View file

@ -20,7 +20,7 @@ AutoCloseFD openLockFile(const Path & path, bool create)
fd = open(path.c_str(), O_CLOEXEC | O_RDWR | (create ? O_CREAT : 0), 0600);
if (!fd && (create || errno != ENOENT))
throw SysError(format("opening lock file '%1%'") % path);
throw SysError("opening lock file '%1%'", path);
return fd;
}
@ -51,7 +51,7 @@ bool lockFile(int fd, LockType lockType, bool wait)
while (flock(fd, type) != 0) {
checkInterrupt();
if (errno != EINTR)
throw SysError(format("acquiring/releasing lock"));
throw SysError("acquiring/releasing lock");
else
return false;
}
@ -60,7 +60,7 @@ bool lockFile(int fd, LockType lockType, bool wait)
checkInterrupt();
if (errno == EWOULDBLOCK) return false;
if (errno != EINTR)
throw SysError(format("acquiring/releasing lock"));
throw SysError("acquiring/releasing lock");
}
}
@ -124,7 +124,7 @@ bool PathLocks::lockPaths(const PathSet & paths,
hasn't been unlinked). */
struct stat st;
if (fstat(fd.get(), &st) == -1)
throw SysError(format("statting lock file '%1%'") % lockPath);
throw SysError("statting lock file '%1%'", lockPath);
if (st.st_size != 0)
/* This lock file has been unlinked, so we're holding
a lock on a deleted file. This means that other
@ -160,7 +160,8 @@ void PathLocks::unlock()
if (close(i.first) == -1)
printError(
format("error (ignored): cannot close lock file on '%1%'") % i.second);
"error (ignored): cannot close lock file on '%1%'",
i.second);
debug(format("lock released on '%1%'") % i.second);
}

View file

@ -50,7 +50,7 @@ Generations findGenerations(Path profile, int & curGen)
gen.number = n;
struct stat st;
if (lstat(gen.path.c_str(), &st) != 0)
throw SysError(format("statting '%1%'") % gen.path);
throw SysError("statting '%1%'", gen.path);
gen.creationTime = st.st_mtime;
gens.push_back(gen);
}
@ -117,7 +117,7 @@ Path createGeneration(ref<LocalFSStore> store, Path profile, Path outPath)
static void removeFile(const Path & path)
{
if (remove(path.c_str()) == -1)
throw SysError(format("cannot unlink '%1%'") % path);
throw SysError("cannot unlink '%1%'", path);
}
@ -149,7 +149,7 @@ void deleteGenerations(const Path & profile, const std::set<unsigned int> & gens
Generations gens = findGenerations(profile, curGen);
if (gensToDelete.find(curGen) != gensToDelete.end())
throw Error(format("cannot delete current generation of profile %1%'") % profile);
throw Error("cannot delete current generation of profile %1%'", profile);
for (auto & i : gens) {
if (gensToDelete.find(i.number) == gensToDelete.end()) continue;
@ -226,7 +226,7 @@ void deleteGenerationsOlderThan(const Path & profile, const string & timeSpec, b
int days;
if (!string2Int(strDays, days) || days < 1)
throw Error(format("invalid number of days specifier '%1%'") % timeSpec);
throw Error("invalid number of days specifier '%1%'", timeSpec);
time_t oldTime = curTime - days * 24 * 3600;

View file

@ -92,7 +92,7 @@ PathSet scanForReferences(const string & path,
auto baseName = std::string(baseNameOf(i));
string::size_type pos = baseName.find('-');
if (pos == string::npos)
throw Error(format("bad reference '%1%'") % i);
throw Error("bad reference '%1%'", i);
string s = string(baseName, 0, pos);
assert(s.size() == refLength);
assert(backMap.find(s) == backMap.end());

View file

@ -51,7 +51,7 @@ std::pair<ref<FSAccessor>, Path> RemoteFSAccessor::fetch(const Path & path_)
std::string restPath = std::string(path, storePath.size());
if (!store->isValidPath(store->parseStorePath(storePath)))
throw InvalidPath(format("path '%1%' is not a valid store path") % storePath);
throw InvalidPath("path '%1%' is not a valid store path", storePath);
auto i = nars.find(storePath);
if (i != nars.end()) return {i->second, restPath};

View file

@ -116,11 +116,11 @@ ref<RemoteStore::Connection> UDSRemoteStore::openConnection()
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
if (socketPath.size() + 1 >= sizeof(addr.sun_path))
throw Error(format("socket path '%1%' is too long") % socketPath);
throw Error("socket path '%1%' is too long", socketPath);
strcpy(addr.sun_path, socketPath.c_str());
if (::connect(conn->fd.get(), (struct sockaddr *) &addr, sizeof(addr)) == -1)
throw SysError(format("cannot connect to daemon at '%1%'") % socketPath);
throw SysError("cannot connect to daemon at '%1%'", socketPath);
conn->from.fd = conn->fd.get();
conn->to.fd = conn->fd.get();
@ -365,7 +365,7 @@ void RemoteStore::queryPathInfoUncached(const StorePath & path,
} catch (Error & e) {
// Ugly backwards compatibility hack.
if (e.msg().find("is not valid") != std::string::npos)
throw InvalidPath(e.what());
throw InvalidPath(e.info());
throw;
}
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 17) {

View file

@ -32,8 +32,10 @@ namespace nix {
struct S3Error : public Error
{
Aws::S3::S3Errors err;
S3Error(Aws::S3::S3Errors err, const FormatOrString & fs)
: Error(fs), err(err) { };
template<typename... Args>
S3Error(Aws::S3::S3Errors err, const Args & ... args)
: Error(args...), err(err) { };
};
/* Helper: given an Outcome<R, E>, return R in case of success, or
@ -109,7 +111,9 @@ class RetryStrategy : public Aws::Client::DefaultRetryStrategy
auto retry = Aws::Client::DefaultRetryStrategy::ShouldRetry(error, attemptedRetries);
if (retry)
printError("AWS error '%s' (%s), will retry in %d ms",
error.GetExceptionName(), error.GetMessage(), CalculateDelayBeforeNextRetry(error, attemptedRetries));
error.GetExceptionName(),
error.GetMessage(),
CalculateDelayBeforeNextRetry(error, attemptedRetries));
return retry;
}
};
@ -249,7 +253,7 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
// If bucket listing is disabled, 404s turn into 403s
|| error.GetErrorType() == Aws::S3::S3Errors::ACCESS_DENIED)
return false;
throw Error(format("AWS error fetching '%s': %s") % path % error.GetMessage());
throw Error("AWS error fetching '%s': %s", path, error.GetMessage());
}
return true;

View file

@ -29,7 +29,7 @@ SQLite::SQLite(const Path & path, bool create)
{
if (sqlite3_open_v2(path.c_str(), &db,
SQLITE_OPEN_READWRITE | (create ? SQLITE_OPEN_CREATE : 0), 0) != SQLITE_OK)
throw Error(format("cannot open SQLite database '%s'") % path);
throw Error("cannot open SQLite database '%s'", path);
if (sqlite3_busy_timeout(db, 60 * 60 * 1000) != SQLITE_OK)
throwSQLiteError(db, "setting timeout");
@ -204,7 +204,10 @@ void handleSQLiteBusy(const SQLiteBusy & e)
if (now > lastWarned + 10) {
lastWarned = now;
printError("warning: %s", e.what());
logWarning(
ErrorInfo { .name = "Sqlite busy",
.hint = hintfmt(e.what())
});
}
/* Sleep for a while since retrying the transaction right away

View file

@ -3,7 +3,7 @@
#include <functional>
#include <string>
#include "types.hh"
#include "error.hh"
struct sqlite3;
struct sqlite3_stmt;

View file

@ -23,7 +23,7 @@ bool Store::isInStore(const Path & path) const
Path Store::toStorePath(const Path & path) const
{
if (!isInStore(path))
throw Error(format("path '%1%' is not in the Nix store") % path);
throw Error("path '%1%' is not in the Nix store", path);
Path::size_type slash = path.find('/', storeDir.size() + 1);
if (slash == Path::npos)
return path;
@ -775,7 +775,11 @@ void ValidPathInfo::sign(const Store & store, const SecretKey & secretKey)
bool ValidPathInfo::isContentAddressed(const Store & store) const
{
auto warn = [&]() {
printError("warning: path '%s' claims to be content-addressed but isn't", store.printStorePath(path));
logWarning(
ErrorInfo{
.name = "Path not content-addressed",
.hint = hintfmt("path '%s' claims to be content-addressed but isn't", store.printStorePath(path))
});
};
if (hasPrefix(ca, "text:")) {
@ -934,7 +938,7 @@ std::list<ref<Store>> getDefaultSubstituters()
try {
stores.push_back(openStore(uri));
} catch (Error & e) {
printError("warning: %s", e.what());
logWarning(e.info());
}
};