Modernize AutoCloseFD

This commit is contained in:
Shea Levy 2016-07-11 15:44:44 -04:00
parent 8a41792d43
commit cb5e7254b6
11 changed files with 139 additions and 153 deletions

View file

@ -325,7 +325,7 @@ RunPager::RunPager()
toPager.create(); toPager.create();
pid = startProcess([&]() { pid = startProcess([&]() {
if (dup2(toPager.readSide, STDIN_FILENO) == -1) if (dup2(toPager.readSide.get(), STDIN_FILENO) == -1)
throw SysError("dupping stdin"); throw SysError("dupping stdin");
if (!getenv("LESS")) if (!getenv("LESS"))
setenv("LESS", "FRSXMK", 1); setenv("LESS", "FRSXMK", 1);
@ -337,7 +337,7 @@ RunPager::RunPager()
throw SysError(format("executing %1%") % pager); throw SysError(format("executing %1%") % pager);
}); });
if (dup2(toPager.writeSide, STDOUT_FILENO) == -1) if (dup2(toPager.writeSide.get(), STDOUT_FILENO) == -1)
throw SysError("dupping stdout"); throw SysError("dupping stdout");
} }

View file

@ -403,7 +403,7 @@ static void commonChildInit(Pipe & logPipe)
throw SysError(format("creating a new session")); throw SysError(format("creating a new session"));
/* Dup the write side of the logger pipe into stderr. */ /* Dup the write side of the logger pipe into stderr. */
if (dup2(logPipe.writeSide, STDERR_FILENO) == -1) if (dup2(logPipe.writeSide.get(), STDERR_FILENO) == -1)
throw SysError("cannot pipe standard error into log file"); throw SysError("cannot pipe standard error into log file");
/* Dup stderr to stdout. */ /* Dup stderr to stdout. */
@ -510,11 +510,11 @@ void UserLock::acquire()
continue; continue;
AutoCloseFD fd = open(fnUserLock.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600); AutoCloseFD fd = open(fnUserLock.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600);
if (fd == -1) if (!fd)
throw SysError(format("opening user lock %1%") % fnUserLock); throw SysError(format("opening user lock %1%") % fnUserLock);
if (lockFile(fd, ltWrite, false)) { if (lockFile(fd.get(), ltWrite, false)) {
fdUserLock = fd.borrow(); fdUserLock = std::move(fd);
lockedPaths.insert(fnUserLock); lockedPaths.insert(fnUserLock);
user = i; user = i;
uid = pw->pw_uid; uid = pw->pw_uid;
@ -550,7 +550,7 @@ void UserLock::acquire()
void UserLock::release() void UserLock::release()
{ {
if (uid == 0) return; if (uid == 0) return;
fdUserLock.close(); /* releases lock */ fdUserLock = -1; /* releases lock */
assert(lockedPaths.find(fnUserLock) != lockedPaths.end()); assert(lockedPaths.find(fnUserLock) != lockedPaths.end());
lockedPaths.erase(fnUserLock); lockedPaths.erase(fnUserLock);
fnUserLock = ""; fnUserLock = "";
@ -613,11 +613,11 @@ HookInstance::HookInstance()
if (chdir("/") == -1) throw SysError("changing into /"); if (chdir("/") == -1) throw SysError("changing into /");
/* Dup the communication pipes. */ /* Dup the communication pipes. */
if (dup2(toHook.readSide, STDIN_FILENO) == -1) if (dup2(toHook.readSide.get(), STDIN_FILENO) == -1)
throw SysError("dupping to-hook read side"); throw SysError("dupping to-hook read side");
/* Use fd 4 for the builder's stdout/stderr. */ /* Use fd 4 for the builder's stdout/stderr. */
if (dup2(builderOut.writeSide, 4) == -1) if (dup2(builderOut.writeSide.get(), 4) == -1)
throw SysError("dupping builder's stdout/stderr"); throw SysError("dupping builder's stdout/stderr");
Strings args = { Strings args = {
@ -633,15 +633,15 @@ HookInstance::HookInstance()
}); });
pid.setSeparatePG(true); pid.setSeparatePG(true);
fromHook.writeSide.close(); fromHook.writeSide = -1;
toHook.readSide.close(); toHook.readSide = -1;
} }
HookInstance::~HookInstance() HookInstance::~HookInstance()
{ {
try { try {
toHook.writeSide.close(); toHook.writeSide = -1;
pid.kill(true); pid.kill(true);
} catch (...) { } catch (...) {
ignoreException(); ignoreException();
@ -1414,10 +1414,10 @@ void DerivationGoal::buildDone()
/* Close the read side of the logger pipe. */ /* Close the read side of the logger pipe. */
if (hook) { if (hook) {
hook->builderOut.readSide.close(); hook->builderOut.readSide = -1;
hook->fromHook.readSide.close(); hook->fromHook.readSide = -1;
} }
else builderOut.readSide.close(); else builderOut.readSide = -1;
/* Close the log file. */ /* Close the log file. */
closeLogFile(); closeLogFile();
@ -1557,7 +1557,7 @@ HookReply DerivationGoal::tryBuildHook()
for (auto & i : features) checkStoreName(i); /* !!! abuse */ for (auto & i : features) checkStoreName(i); /* !!! abuse */
/* Send the request to the hook. */ /* Send the request to the hook. */
writeLine(worker.hook->toHook.writeSide, (format("%1% %2% %3% %4%") writeLine(worker.hook->toHook.writeSide.get(), (format("%1% %2% %3% %4%")
% (worker.getNrLocalBuilds() < settings.maxBuildJobs ? "1" : "0") % (worker.getNrLocalBuilds() < settings.maxBuildJobs ? "1" : "0")
% drv->platform % drvPath % concatStringsSep(",", features)).str()); % drv->platform % drvPath % concatStringsSep(",", features)).str());
@ -1565,7 +1565,7 @@ HookReply DerivationGoal::tryBuildHook()
whether the hook wishes to perform the build. */ whether the hook wishes to perform the build. */
string reply; string reply;
while (true) { while (true) {
string s = readLine(worker.hook->fromHook.readSide); string s = readLine(worker.hook->fromHook.readSide.get());
if (string(s, 0, 2) == "# ") { if (string(s, 0, 2) == "# ") {
reply = string(s, 2); reply = string(s, 2);
break; break;
@ -1597,22 +1597,22 @@ HookReply DerivationGoal::tryBuildHook()
string s; string s;
for (auto & i : allInputs) { s += i; s += ' '; } for (auto & i : allInputs) { s += i; s += ' '; }
writeLine(hook->toHook.writeSide, s); writeLine(hook->toHook.writeSide.get(), s);
/* Tell the hooks the missing outputs that have to be copied back /* Tell the hooks the missing outputs that have to be copied back
from the remote system. */ from the remote system. */
s = ""; s = "";
for (auto & i : missingPaths) { s += i; s += ' '; } for (auto & i : missingPaths) { s += i; s += ' '; }
writeLine(hook->toHook.writeSide, s); writeLine(hook->toHook.writeSide.get(), s);
hook->toHook.writeSide.close(); hook->toHook.writeSide = -1;
/* Create the log file and pipe. */ /* Create the log file and pipe. */
Path logFile = openLogFile(); Path logFile = openLogFile();
set<int> fds; set<int> fds;
fds.insert(hook->fromHook.readSide); fds.insert(hook->fromHook.readSide.get());
fds.insert(hook->builderOut.readSide); fds.insert(hook->builderOut.readSide.get());
worker.childStarted(shared_from_this(), fds, false, false); worker.childStarted(shared_from_this(), fds, false, false);
return rpAccept; return rpAccept;
@ -2142,17 +2142,17 @@ void DerivationGoal::startBuilder()
child = clone(childEntry, stack + stackSize, flags & ~CLONE_NEWPID, this); child = clone(childEntry, stack + stackSize, flags & ~CLONE_NEWPID, this);
if (child == -1) throw SysError("cloning builder process"); if (child == -1) throw SysError("cloning builder process");
writeFull(builderOut.writeSide, std::to_string(child) + "\n"); writeFull(builderOut.writeSide.get(), std::to_string(child) + "\n");
_exit(0); _exit(0);
}, options); }, options);
if (helper.wait(true) != 0) if (helper.wait(true) != 0)
throw Error("unable to start build process"); throw Error("unable to start build process");
userNamespaceSync.readSide.close(); userNamespaceSync.readSide = -1;
pid_t tmp; pid_t tmp;
if (!string2Int<pid_t>(readLine(builderOut.readSide), tmp)) abort(); if (!string2Int<pid_t>(readLine(builderOut.readSide.get()), tmp)) abort();
pid = tmp; pid = tmp;
/* Set the UID/GID mapping of the builder's user /* Set the UID/GID mapping of the builder's user
@ -2171,8 +2171,8 @@ void DerivationGoal::startBuilder()
/* Signal the builder that we've updated its user /* Signal the builder that we've updated its user
namespace. */ namespace. */
writeFull(userNamespaceSync.writeSide, "1"); writeFull(userNamespaceSync.writeSide.get(), "1");
userNamespaceSync.writeSide.close(); userNamespaceSync.writeSide = -1;
} else } else
#endif #endif
@ -2186,12 +2186,12 @@ void DerivationGoal::startBuilder()
/* parent */ /* parent */
pid.setSeparatePG(true); pid.setSeparatePG(true);
builderOut.writeSide.close(); builderOut.writeSide = -1;
worker.childStarted(shared_from_this(), {builderOut.readSide}, true, true); worker.childStarted(shared_from_this(), {builderOut.readSide.get()}, true, true);
/* Check if setting up the build environment failed. */ /* Check if setting up the build environment failed. */
while (true) { while (true) {
string msg = readLine(builderOut.readSide); string msg = readLine(builderOut.readSide.get());
if (string(msg, 0, 1) == "\1") { if (string(msg, 0, 1) == "\1") {
if (msg.size() == 1) break; if (msg.size() == 1) break;
throw Error(string(msg, 1)); throw Error(string(msg, 1));
@ -2215,26 +2215,24 @@ void DerivationGoal::runChild()
#if __linux__ #if __linux__
if (useChroot) { if (useChroot) {
userNamespaceSync.writeSide.close(); userNamespaceSync.writeSide = -1;
if (drainFD(userNamespaceSync.readSide) != "1") if (drainFD(userNamespaceSync.readSide.get()) != "1")
throw Error("user namespace initialisation failed"); throw Error("user namespace initialisation failed");
userNamespaceSync.readSide.close(); userNamespaceSync.readSide = -1;
if (privateNetwork) { if (privateNetwork) {
/* Initialise the loopback interface. */ /* Initialise the loopback interface. */
AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)); AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
if (fd == -1) throw SysError("cannot open IP socket"); if (!fd) throw SysError("cannot open IP socket");
struct ifreq ifr; struct ifreq ifr;
strcpy(ifr.ifr_name, "lo"); strcpy(ifr.ifr_name, "lo");
ifr.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING; ifr.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) if (ioctl(fd.get(), SIOCSIFFLAGS, &ifr) == -1)
throw SysError("cannot set loopback interface flags"); throw SysError("cannot set loopback interface flags");
fd.close();
} }
/* Set the hostname etc. to fixed values. */ /* Set the hostname etc. to fixed values. */
@ -2919,9 +2917,9 @@ Path DerivationGoal::openLogFile()
% (settings.compressLog ? ".bz2" : "")).str(); % (settings.compressLog ? ".bz2" : "")).str();
fdLogFile = open(logFileName.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0666); fdLogFile = open(logFileName.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0666);
if (fdLogFile == -1) throw SysError(format("creating log file %1%") % logFileName); if (!fdLogFile) throw SysError(format("creating log file %1%") % logFileName);
logFileSink = std::make_shared<FdSink>(fdLogFile); logFileSink = std::make_shared<FdSink>(fdLogFile.get());
if (settings.compressLog) if (settings.compressLog)
logSink = std::shared_ptr<CompressionSink>(makeCompressionSink("bzip2", *logFileSink)); logSink = std::shared_ptr<CompressionSink>(makeCompressionSink("bzip2", *logFileSink));
@ -2938,7 +2936,7 @@ void DerivationGoal::closeLogFile()
if (logSink2) logSink2->finish(); if (logSink2) logSink2->finish();
if (logFileSink) logFileSink->flush(); if (logFileSink) logFileSink->flush();
logSink = logFileSink = 0; logSink = logFileSink = 0;
fdLogFile.close(); fdLogFile = -1;
} }
@ -2960,8 +2958,8 @@ void DerivationGoal::deleteTmpDir(bool force)
void DerivationGoal::handleChildOutput(int fd, const string & data) void DerivationGoal::handleChildOutput(int fd, const string & data)
{ {
if ((hook && fd == hook->builderOut.readSide) || if ((hook && fd == hook->builderOut.readSide.get()) ||
(!hook && fd == builderOut.readSide)) (!hook && fd == builderOut.readSide.get()))
{ {
logSize += data.size(); logSize += data.size();
if (settings.maxLogSize && logSize > settings.maxLogSize) { if (settings.maxLogSize && logSize > settings.maxLogSize) {
@ -2987,7 +2985,7 @@ void DerivationGoal::handleChildOutput(int fd, const string & data)
if (logSink) (*logSink)(data); if (logSink) (*logSink)(data);
} }
if (hook && fd == hook->fromHook.readSide) if (hook && fd == hook->fromHook.readSide.get())
printMsg(lvlError, data); // FIXME? printMsg(lvlError, data); // FIXME?
} }
@ -3274,7 +3272,7 @@ void SubstitutionGoal::tryToRun()
thr = std::thread([this]() { thr = std::thread([this]() {
try { try {
/* Wake up the worker loop when we're done. */ /* Wake up the worker loop when we're done. */
Finally updateStats([this]() { outPipe.writeSide.close(); }); Finally updateStats([this]() { outPipe.writeSide = -1; });
copyStorePath(ref<Store>(sub), ref<Store>(worker.store.shared_from_this()), copyStorePath(ref<Store>(sub), ref<Store>(worker.store.shared_from_this()),
storePath, repair); storePath, repair);
@ -3285,7 +3283,7 @@ void SubstitutionGoal::tryToRun()
} }
}); });
worker.childStarted(shared_from_this(), {outPipe.readSide}, true, false); worker.childStarted(shared_from_this(), {outPipe.readSide.get()}, true, false);
state = &SubstitutionGoal::finished; state = &SubstitutionGoal::finished;
} }
@ -3325,7 +3323,7 @@ void SubstitutionGoal::handleChildOutput(int fd, const string & data)
void SubstitutionGoal::handleEOF(int fd) void SubstitutionGoal::handleEOF(int fd)
{ {
if (fd == outPipe.readSide) worker.wakeUp(shared_from_this()); if (fd == outPipe.readSide.get()) worker.wakeUp(shared_from_this());
} }

View file

@ -34,19 +34,19 @@ int LocalStore::openGCLock(LockType lockType)
debug(format("acquiring global GC lock %1%") % fnGCLock); debug(format("acquiring global GC lock %1%") % fnGCLock);
AutoCloseFD fdGCLock = open(fnGCLock.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600); AutoCloseFD fdGCLock = open(fnGCLock.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600);
if (fdGCLock == -1) if (!fdGCLock)
throw SysError(format("opening global GC lock %1%") % fnGCLock); throw SysError(format("opening global GC lock %1%") % fnGCLock);
if (!lockFile(fdGCLock, lockType, false)) { if (!lockFile(fdGCLock.get(), lockType, false)) {
printMsg(lvlError, format("waiting for the big garbage collector lock...")); printMsg(lvlError, format("waiting for the big garbage collector lock..."));
lockFile(fdGCLock, lockType, true); lockFile(fdGCLock.get(), lockType, true);
} }
/* !!! Restrict read permission on the GC root. Otherwise any /* !!! Restrict read permission on the GC root. Otherwise any
process that can open the file for reading can DoS the process that can open the file for reading can DoS the
collector. */ collector. */
return fdGCLock.borrow(); return fdGCLock.release();
} }
@ -149,7 +149,7 @@ void LocalStore::addTempRoot(const Path & path)
auto state(_state.lock()); auto state(_state.lock());
/* Create the temporary roots file for this process. */ /* Create the temporary roots file for this process. */
if (state->fdTempRoots == -1) { if (!state->fdTempRoots) {
while (1) { while (1) {
Path dir = (format("%1%/%2%") % stateDir % tempRootsDir).str(); Path dir = (format("%1%/%2%") % stateDir % tempRootsDir).str();
@ -166,15 +166,15 @@ void LocalStore::addTempRoot(const Path & path)
state->fdTempRoots = openLockFile(state->fnTempRoots, true); state->fdTempRoots = openLockFile(state->fnTempRoots, true);
fdGCLock.close(); fdGCLock = -1;
debug(format("acquiring read lock on %1%") % state->fnTempRoots); debug(format("acquiring read lock on %1%") % state->fnTempRoots);
lockFile(state->fdTempRoots, ltRead, true); lockFile(state->fdTempRoots.get(), ltRead, true);
/* Check whether the garbage collector didn't get in our /* Check whether the garbage collector didn't get in our
way. */ way. */
struct stat st; struct stat st;
if (fstat(state->fdTempRoots, &st) == -1) if (fstat(state->fdTempRoots.get(), &st) == -1)
throw SysError(format("statting %1%") % state->fnTempRoots); throw SysError(format("statting %1%") % state->fnTempRoots);
if (st.st_size == 0) break; if (st.st_size == 0) break;
@ -188,14 +188,14 @@ void LocalStore::addTempRoot(const Path & path)
/* Upgrade the lock to a write lock. This will cause us to block /* Upgrade the lock to a write lock. This will cause us to block
if the garbage collector is holding our lock. */ if the garbage collector is holding our lock. */
debug(format("acquiring write lock on %1%") % state->fnTempRoots); debug(format("acquiring write lock on %1%") % state->fnTempRoots);
lockFile(state->fdTempRoots, ltWrite, true); lockFile(state->fdTempRoots.get(), ltWrite, true);
string s = path + '\0'; string s = path + '\0';
writeFull(state->fdTempRoots, s); writeFull(state->fdTempRoots.get(), s);
/* Downgrade to a read lock. */ /* Downgrade to a read lock. */
debug(format("downgrading to read lock on %1%") % state->fnTempRoots); debug(format("downgrading to read lock on %1%") % state->fnTempRoots);
lockFile(state->fdTempRoots, ltRead, true); lockFile(state->fdTempRoots.get(), ltRead, true);
} }
@ -211,7 +211,7 @@ void LocalStore::readTempRoots(PathSet & tempRoots, FDs & fds)
debug(format("reading temporary root file %1%") % path); debug(format("reading temporary root file %1%") % path);
FDPtr fd(new AutoCloseFD(open(path.c_str(), O_CLOEXEC | O_RDWR, 0666))); FDPtr fd(new AutoCloseFD(open(path.c_str(), O_CLOEXEC | O_RDWR, 0666)));
if (*fd == -1) { if (!*fd) {
/* It's okay if the file has disappeared. */ /* It's okay if the file has disappeared. */
if (errno == ENOENT) continue; if (errno == ENOENT) continue;
throw SysError(format("opening temporary roots file %1%") % path); throw SysError(format("opening temporary roots file %1%") % path);
@ -224,10 +224,10 @@ void LocalStore::readTempRoots(PathSet & tempRoots, FDs & fds)
/* Try to acquire a write lock without blocking. This can /* Try to acquire a write lock without blocking. This can
only succeed if the owning process has died. In that case only succeed if the owning process has died. In that case
we don't care about its temporary roots. */ we don't care about its temporary roots. */
if (lockFile(*fd, ltWrite, false)) { if (lockFile(fd->get(), ltWrite, false)) {
printMsg(lvlError, format("removing stale temporary roots file %1%") % path); printMsg(lvlError, format("removing stale temporary roots file %1%") % path);
unlink(path.c_str()); unlink(path.c_str());
writeFull(*fd, "d"); writeFull(fd->get(), "d");
continue; continue;
} }
@ -235,10 +235,10 @@ void LocalStore::readTempRoots(PathSet & tempRoots, FDs & fds)
from upgrading to a write lock, therefore it will block in from upgrading to a write lock, therefore it will block in
addTempRoot(). */ addTempRoot(). */
debug(format("waiting for read lock on %1%") % path); debug(format("waiting for read lock on %1%") % path);
lockFile(*fd, ltRead, true); lockFile(fd->get(), ltRead, true);
/* Read the entire file. */ /* Read the entire file. */
string contents = readFile(*fd); string contents = readFile(fd->get());
/* Extract the roots. */ /* Extract the roots. */
string::size_type pos = 0, end; string::size_type pos = 0, end;
@ -721,7 +721,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
} }
/* Allow other processes to add to the store from here on. */ /* Allow other processes to add to the store from here on. */
fdGCLock.close(); fdGCLock = -1;
fds.clear(); fds.clear();
/* Delete the trash directory. */ /* Delete the trash directory. */

View file

@ -120,11 +120,11 @@ LocalStore::LocalStore(const Params & params)
AutoCloseFD fd = open(reservedPath.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, 0600); AutoCloseFD fd = open(reservedPath.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, 0600);
int res = -1; int res = -1;
#if HAVE_POSIX_FALLOCATE #if HAVE_POSIX_FALLOCATE
res = posix_fallocate(fd, 0, settings.reservedSize); res = posix_fallocate(fd.get(), 0, settings.reservedSize);
#endif #endif
if (res == -1) { if (res == -1) {
writeFull(fd, string(settings.reservedSize, 'X')); writeFull(fd.get(), string(settings.reservedSize, 'X'));
ftruncate(fd, settings.reservedSize); ftruncate(fd.get(), settings.reservedSize);
} }
} }
} catch (SysError & e) { /* don't care about errors */ } catch (SysError & e) { /* don't care about errors */
@ -135,9 +135,9 @@ LocalStore::LocalStore(const Params & params)
Path globalLockPath = dbDir + "/big-lock"; Path globalLockPath = dbDir + "/big-lock";
globalLock = openLockFile(globalLockPath.c_str(), true); globalLock = openLockFile(globalLockPath.c_str(), true);
if (!lockFile(globalLock, ltRead, false)) { if (!lockFile(globalLock.get(), ltRead, false)) {
printMsg(lvlError, "waiting for the big Nix store lock..."); printMsg(lvlError, "waiting for the big Nix store lock...");
lockFile(globalLock, ltRead, true); lockFile(globalLock.get(), ltRead, true);
} }
/* Check the current database schema and if necessary do an /* Check the current database schema and if necessary do an
@ -166,9 +166,9 @@ LocalStore::LocalStore(const Params & params)
"which is no longer supported. To convert to the new format,\n" "which is no longer supported. To convert to the new format,\n"
"please upgrade Nix to version 1.11 first."); "please upgrade Nix to version 1.11 first.");
if (!lockFile(globalLock, ltWrite, false)) { if (!lockFile(globalLock.get(), ltWrite, false)) {
printMsg(lvlError, "waiting for exclusive access to the Nix store..."); printMsg(lvlError, "waiting for exclusive access to the Nix store...");
lockFile(globalLock, ltWrite, true); lockFile(globalLock.get(), ltWrite, true);
} }
/* Get the schema version again, because another process may /* Get the schema version again, because another process may
@ -197,7 +197,7 @@ LocalStore::LocalStore(const Params & params)
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str()); writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
lockFile(globalLock, ltRead, true); lockFile(globalLock.get(), ltRead, true);
} }
else openDB(*state, false); else openDB(*state, false);
@ -236,8 +236,8 @@ LocalStore::~LocalStore()
auto state(_state.lock()); auto state(_state.lock());
try { try {
if (state->fdTempRoots != -1) { if (state->fdTempRoots) {
state->fdTempRoots.close(); state->fdTempRoots = -1;
unlink(state->fnTempRoots.c_str()); unlink(state->fnTempRoots.c_str());
} }
} catch (...) { } catch (...) {
@ -1115,7 +1115,7 @@ bool LocalStore::verifyStore(bool checkContents, bool repair)
/* Release the GC lock so that checking content hashes (which can /* Release the GC lock so that checking content hashes (which can
take ages) doesn't block the GC or builds. */ take ages) doesn't block the GC or builds. */
fdGCLock.close(); fdGCLock = -1;
/* Optionally, check the content hashes (slow). */ /* Optionally, check the content hashes (slow). */
if (checkContents) { if (checkContents) {

View file

@ -17,10 +17,10 @@ int openLockFile(const Path & path, bool create)
AutoCloseFD fd; AutoCloseFD fd;
fd = open(path.c_str(), O_CLOEXEC | O_RDWR | (create ? O_CREAT : 0), 0600); fd = open(path.c_str(), O_CLOEXEC | O_RDWR | (create ? O_CREAT : 0), 0600);
if (fd == -1 && (create || errno != ENOENT)) if (!fd && (create || errno != ENOENT))
throw SysError(format("opening lock file %1%") % path); throw SysError(format("opening lock file %1%") % path);
return fd.borrow(); return fd.release();
} }
@ -119,10 +119,10 @@ bool PathLocks::lockPaths(const PathSet & _paths,
fd = openLockFile(lockPath, true); fd = openLockFile(lockPath, true);
/* Acquire an exclusive lock. */ /* Acquire an exclusive lock. */
if (!lockFile(fd, ltWrite, false)) { if (!lockFile(fd.get(), ltWrite, false)) {
if (wait) { if (wait) {
if (waitMsg != "") printMsg(lvlError, waitMsg); if (waitMsg != "") printMsg(lvlError, waitMsg);
lockFile(fd, ltWrite, true); lockFile(fd.get(), ltWrite, true);
} else { } else {
/* Failed to lock this path; release all other /* Failed to lock this path; release all other
locks. */ locks. */
@ -136,7 +136,7 @@ bool PathLocks::lockPaths(const PathSet & _paths,
/* Check that the lock file hasn't become stale (i.e., /* Check that the lock file hasn't become stale (i.e.,
hasn't been unlinked). */ hasn't been unlinked). */
struct stat st; struct stat st;
if (fstat(fd, &st) == -1) if (fstat(fd.get(), &st) == -1)
throw SysError(format("statting lock file %1%") % lockPath); throw SysError(format("statting lock file %1%") % lockPath);
if (st.st_size != 0) if (st.st_size != 0)
/* This lock file has been unlinked, so we're holding /* This lock file has been unlinked, so we're holding
@ -149,7 +149,7 @@ bool PathLocks::lockPaths(const PathSet & _paths,
} }
/* Use borrow so that the descriptor isn't closed. */ /* Use borrow so that the descriptor isn't closed. */
fds.push_back(FDPair(fd.borrow(), lockPath)); fds.push_back(FDPair(fd.release(), lockPath));
lockedPaths.insert(lockPath); lockedPaths.insert(lockPath);
} }

View file

@ -66,9 +66,9 @@ ref<RemoteStore::Connection> RemoteStore::openConnection()
| SOCK_CLOEXEC | SOCK_CLOEXEC
#endif #endif
, 0); , 0);
if (conn->fd == -1) if (!conn->fd)
throw SysError("cannot create Unix domain socket"); throw SysError("cannot create Unix domain socket");
closeOnExec(conn->fd); closeOnExec(conn->fd.get());
string socketPath = settings.nixDaemonSocketFile; string socketPath = settings.nixDaemonSocketFile;
@ -78,11 +78,11 @@ ref<RemoteStore::Connection> RemoteStore::openConnection()
throw Error(format("socket path %1% is too long") % socketPath); throw Error(format("socket path %1% is too long") % socketPath);
strcpy(addr.sun_path, socketPath.c_str()); strcpy(addr.sun_path, socketPath.c_str());
if (connect(conn->fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) if (connect(conn->fd.get(), (struct sockaddr *) &addr, sizeof(addr)) == -1)
throw SysError(format("cannot connect to daemon at %1%") % socketPath); throw SysError(format("cannot connect to daemon at %1%") % socketPath);
conn->from.fd = conn->fd; conn->from.fd = conn->fd.get();
conn->to.fd = conn->fd; conn->to.fd = conn->fd.get();
/* Send the magic greeting, check for the reply. */ /* Send the magic greeting, check for the reply. */
try { try {
@ -531,7 +531,7 @@ RemoteStore::Connection::~Connection()
{ {
try { try {
to.flush(); to.flush();
fd.close(); fd = -1;
} catch (...) { } catch (...) {
ignoreException(); ignoreException();
} }

View file

@ -42,14 +42,14 @@ static void dumpContents(const Path & path, size_t size,
sink << "contents" << size; sink << "contents" << size;
AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_CLOEXEC); AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
if (fd == -1) throw SysError(format("opening file %1%") % path); if (!fd) throw SysError(format("opening file %1%") % path);
unsigned char buf[65536]; unsigned char buf[65536];
size_t left = size; size_t left = size;
while (left > 0) { while (left > 0) {
size_t n = left > sizeof(buf) ? sizeof(buf) : left; size_t n = left > sizeof(buf) ? sizeof(buf) : left;
readFull(fd, buf, n); readFull(fd.get(), buf, n);
left -= n; left -= n;
sink(buf, n); sink(buf, n);
} }
@ -303,17 +303,16 @@ struct RestoreSink : ParseSink
void createRegularFile(const Path & path) void createRegularFile(const Path & path)
{ {
Path p = dstPath + path; Path p = dstPath + path;
fd.close();
fd = open(p.c_str(), O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC, 0666); fd = open(p.c_str(), O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC, 0666);
if (fd == -1) throw SysError(format("creating file %1%") % p); if (!fd) throw SysError(format("creating file %1%") % p);
} }
void isExecutable() void isExecutable()
{ {
struct stat st; struct stat st;
if (fstat(fd, &st) == -1) if (fstat(fd.get(), &st) == -1)
throw SysError("fstat"); throw SysError("fstat");
if (fchmod(fd, st.st_mode | (S_IXUSR | S_IXGRP | S_IXOTH)) == -1) if (fchmod(fd.get(), st.st_mode | (S_IXUSR | S_IXGRP | S_IXOTH)) == -1)
throw SysError("fchmod"); throw SysError("fchmod");
} }
@ -321,7 +320,7 @@ struct RestoreSink : ParseSink
{ {
#if HAVE_POSIX_FALLOCATE #if HAVE_POSIX_FALLOCATE
if (len) { if (len) {
errno = posix_fallocate(fd, 0, len); errno = posix_fallocate(fd.get(), 0, len);
/* Note that EINVAL may indicate that the underlying /* Note that EINVAL may indicate that the underlying
filesystem doesn't support preallocation (e.g. on filesystem doesn't support preallocation (e.g. on
OpenSolaris). Since preallocation is just an OpenSolaris). Since preallocation is just an
@ -334,7 +333,7 @@ struct RestoreSink : ParseSink
void receiveContents(unsigned char * data, unsigned int len) void receiveContents(unsigned char * data, unsigned int len)
{ {
writeFull(fd, data, len); writeFull(fd.get(), data, len);
} }
void createSymlink(const Path & path, const string & target) void createSymlink(const Path & path, const string & target)

View file

@ -255,11 +255,11 @@ Hash hashFile(HashType ht, const Path & path)
start(ht, ctx); start(ht, ctx);
AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_CLOEXEC); AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
if (fd == -1) throw SysError(format("opening file %1%") % path); if (!fd) throw SysError(format("opening file %1%") % path);
unsigned char buf[8192]; unsigned char buf[8192];
ssize_t n; ssize_t n;
while ((n = read(fd, buf, sizeof(buf)))) { while ((n = read(fd.get(), buf, sizeof(buf)))) {
checkInterrupt(); checkInterrupt();
if (n == -1) throw SysError(format("reading file %1%") % path); if (n == -1) throw SysError(format("reading file %1%") % path);
update(ht, ctx, buf, n); update(ht, ctx, buf, n);

View file

@ -274,18 +274,18 @@ string readFile(int fd)
string readFile(const Path & path, bool drain) string readFile(const Path & path, bool drain)
{ {
AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_CLOEXEC); AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
if (fd == -1) if (!fd)
throw SysError(format("opening file %1%") % path); throw SysError(format("opening file %1%") % path);
return drain ? drainFD(fd) : readFile(fd); return drain ? drainFD(fd.get()) : readFile(fd.get());
} }
void writeFile(const Path & path, const string & s) void writeFile(const Path & path, const string & s)
{ {
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0666); AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0666);
if (fd == -1) if (!fd)
throw SysError(format("opening file %1%") % path); throw SysError(format("opening file %1%") % path);
writeFull(fd, s); writeFull(fd.get(), s);
} }
@ -556,28 +556,24 @@ void AutoDelete::reset(const Path & p, bool recursive) {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
AutoCloseFD::AutoCloseFD() AutoCloseFD::AutoCloseFD() : fd{-1} {}
AutoCloseFD::AutoCloseFD(int fd) : fd{fd} {}
AutoCloseFD::AutoCloseFD(AutoCloseFD&& that) : fd{that.fd}
{ {
fd = -1; that.fd = -1;
} }
AutoCloseFD::AutoCloseFD(int fd) AutoCloseFD& AutoCloseFD::operator =(AutoCloseFD&& that)
{ {
this->fd = fd; close();
} fd = that.fd;
that.fd = -1;
return *this;
AutoCloseFD::AutoCloseFD(const AutoCloseFD & fd)
{
/* Copying an AutoCloseFD isn't allowed (who should get to close
it?). But as an edge case, allow copying of closed
AutoCloseFDs. This is necessary due to tiresome reasons
involving copy constructor use on default object values in STL
containers (like when you do `map[value]' where value isn't in
the map yet). */
this->fd = fd.fd;
if (this->fd != -1) abort();
} }
@ -591,14 +587,7 @@ AutoCloseFD::~AutoCloseFD()
} }
void AutoCloseFD::operator =(int fd) int AutoCloseFD::get() const
{
if (this->fd != fd) close();
this->fd = fd;
}
AutoCloseFD::operator int() const
{ {
return fd; return fd;
} }
@ -610,19 +599,17 @@ void AutoCloseFD::close()
if (::close(fd) == -1) if (::close(fd) == -1)
/* This should never happen. */ /* This should never happen. */
throw SysError(format("closing file descriptor %1%") % fd); throw SysError(format("closing file descriptor %1%") % fd);
fd = -1;
} }
} }
bool AutoCloseFD::isOpen() AutoCloseFD::operator bool() const
{ {
return fd != -1; return fd != -1;
} }
/* Pass responsibility for closing this fd to the caller. */ int AutoCloseFD::release()
int AutoCloseFD::borrow()
{ {
int oldFD = fd; int oldFD = fd;
fd = -1; fd = -1;
@ -899,10 +886,10 @@ string runProgram(Path program, bool searchPath, const Strings & args,
/* Fork. */ /* Fork. */
Pid pid = startProcess([&]() { Pid pid = startProcess([&]() {
if (dup2(out.writeSide, STDOUT_FILENO) == -1) if (dup2(out.writeSide.get(), STDOUT_FILENO) == -1)
throw SysError("dupping stdout"); throw SysError("dupping stdout");
if (!input.empty()) { if (!input.empty()) {
if (dup2(in.readSide, STDIN_FILENO) == -1) if (dup2(in.readSide.get(), STDIN_FILENO) == -1)
throw SysError("dupping stdin"); throw SysError("dupping stdin");
} }
@ -917,16 +904,16 @@ string runProgram(Path program, bool searchPath, const Strings & args,
throw SysError(format("executing %1%") % program); throw SysError(format("executing %1%") % program);
}); });
out.writeSide.close(); out.writeSide = -1;
/* FIXME: This can deadlock if the input is too long. */ /* FIXME: This can deadlock if the input is too long. */
if (!input.empty()) { if (!input.empty()) {
in.readSide.close(); in.readSide = -1;
writeFull(in.writeSide, input); writeFull(in.writeSide.get(), input);
in.writeSide.close(); in.writeSide = -1;
} }
string result = drainFD(out.readSide); string result = drainFD(out.readSide.get());
/* Wait for the child to finish. */ /* Wait for the child to finish. */
int status = pid.wait(true); int status = pid.wait(true);

View file

@ -164,16 +164,18 @@ public:
class AutoCloseFD class AutoCloseFD
{ {
int fd; int fd;
void close();
public: public:
AutoCloseFD(); AutoCloseFD();
AutoCloseFD(int fd); AutoCloseFD(int fd);
AutoCloseFD(const AutoCloseFD & fd); AutoCloseFD(const AutoCloseFD & fd) = delete;
AutoCloseFD(AutoCloseFD&& fd);
~AutoCloseFD(); ~AutoCloseFD();
void operator =(int fd); AutoCloseFD& operator =(const AutoCloseFD & fd) = delete;
operator int() const; AutoCloseFD& operator =(AutoCloseFD&& fd);
void close(); int get() const;
bool isOpen(); explicit operator bool() const;
int borrow(); int release();
}; };

View file

@ -767,7 +767,7 @@ static void daemonLoop(char * * argv)
/* Create and bind to a Unix domain socket. */ /* Create and bind to a Unix domain socket. */
fdSocket = socket(PF_UNIX, SOCK_STREAM, 0); fdSocket = socket(PF_UNIX, SOCK_STREAM, 0);
if (fdSocket == -1) if (!fdSocket)
throw SysError("cannot create Unix domain socket"); throw SysError("cannot create Unix domain socket");
string socketPath = settings.nixDaemonSocketFile; string socketPath = settings.nixDaemonSocketFile;
@ -793,7 +793,7 @@ static void daemonLoop(char * * argv)
(everybody can connect --- provided they have access to the (everybody can connect --- provided they have access to the
directory containing the socket). */ directory containing the socket). */
mode_t oldMode = umask(0111); mode_t oldMode = umask(0111);
int res = bind(fdSocket, (struct sockaddr *) &addr, sizeof(addr)); int res = bind(fdSocket.get(), (struct sockaddr *) &addr, sizeof(addr));
umask(oldMode); umask(oldMode);
if (res == -1) if (res == -1)
throw SysError(format("cannot bind to socket %1%") % socketPath); throw SysError(format("cannot bind to socket %1%") % socketPath);
@ -801,11 +801,11 @@ static void daemonLoop(char * * argv)
if (chdir("/") == -1) /* back to the root */ if (chdir("/") == -1) /* back to the root */
throw SysError("cannot change current directory"); throw SysError("cannot change current directory");
if (listen(fdSocket, 5) == -1) if (listen(fdSocket.get(), 5) == -1)
throw SysError(format("cannot listen on socket %1%") % socketPath); throw SysError(format("cannot listen on socket %1%") % socketPath);
} }
closeOnExec(fdSocket); closeOnExec(fdSocket.get());
/* Loop accepting connections. */ /* Loop accepting connections. */
while (1) { while (1) {
@ -815,18 +815,18 @@ static void daemonLoop(char * * argv)
struct sockaddr_un remoteAddr; struct sockaddr_un remoteAddr;
socklen_t remoteAddrLen = sizeof(remoteAddr); socklen_t remoteAddrLen = sizeof(remoteAddr);
AutoCloseFD remote = accept(fdSocket, AutoCloseFD remote = accept(fdSocket.get(),
(struct sockaddr *) &remoteAddr, &remoteAddrLen); (struct sockaddr *) &remoteAddr, &remoteAddrLen);
checkInterrupt(); checkInterrupt();
if (remote == -1) { if (!remote) {
if (errno == EINTR) continue; if (errno == EINTR) continue;
throw SysError("accepting connection"); throw SysError("accepting connection");
} }
closeOnExec(remote); closeOnExec(remote.get());
bool trusted = false; bool trusted = false;
PeerInfo peer = getPeerInfo(remote); PeerInfo peer = getPeerInfo(remote.get());
struct passwd * pw = peer.uidKnown ? getpwuid(peer.uid) : 0; struct passwd * pw = peer.uidKnown ? getpwuid(peer.uid) : 0;
string user = pw ? pw->pw_name : std::to_string(peer.uid); string user = pw ? pw->pw_name : std::to_string(peer.uid);
@ -854,7 +854,7 @@ static void daemonLoop(char * * argv)
options.runExitHandlers = true; options.runExitHandlers = true;
options.allowVfork = false; options.allowVfork = false;
startProcess([&]() { startProcess([&]() {
fdSocket.close(); fdSocket = -1;
/* Background the daemon. */ /* Background the daemon. */
if (setsid() == -1) if (setsid() == -1)
@ -870,8 +870,8 @@ static void daemonLoop(char * * argv)
} }
/* Handle the connection. */ /* Handle the connection. */
from.fd = remote; from.fd = remote.get();
to.fd = remote; to.fd = remote.get();
processConnection(trusted); processConnection(trusted);
exit(0); exit(0);