libutil: Add bindPath function from libstore

bindPath/doBind is a useful function in build that is used in several
parts of LocalDerivationGoal. Moving this function makes it easier to
split LocalDerivationGoal implementation between several files.

Change-Id: Ic5a0768479c153c1aa3ed425f12604b20bbf0f42
This commit is contained in:
Artemis Tosini 2024-07-27 19:40:40 +00:00
parent 6abad7cb23
commit 3058029fba
No known key found for this signature in database
GPG key ID: EE5227935FE3FF18
4 changed files with 67 additions and 38 deletions

View file

@ -17,6 +17,7 @@
#include "namespaces.hh" #include "namespaces.hh"
#include "child.hh" #include "child.hh"
#include "unix-domain-socket.hh" #include "unix-domain-socket.hh"
#include "mount.hh"
#include <regex> #include <regex>
#include <queue> #include <queue>
@ -386,39 +387,6 @@ void LocalDerivationGoal::cleanupPostOutputsRegisteredModeNonCheck()
cleanupPostOutputsRegisteredModeCheck(); cleanupPostOutputsRegisteredModeCheck();
} }
#if __linux__
static void doBind(const Path & source, const Path & target, bool optional = false) {
debug("bind mounting '%1%' to '%2%'", source, target);
auto bindMount = [&]() {
if (mount(source.c_str(), target.c_str(), "", MS_BIND | MS_REC, 0) == -1)
throw SysError("bind mount from '%1%' to '%2%' failed", source, target);
};
auto maybeSt = maybeLstat(source);
if (!maybeSt) {
if (optional)
return;
else
throw SysError("getting attributes of path '%1%'", source);
}
auto st = *maybeSt;
if (S_ISDIR(st.st_mode)) {
createDirs(target);
bindMount();
} else if (S_ISLNK(st.st_mode)) {
// Symlinks can (apparently) not be bind-mounted, so just copy it
createDirs(dirOf(target));
copyFile(source, target, {});
} else {
createDirs(dirOf(target));
writeFile(target, "");
bindMount();
}
};
#endif
void LocalDerivationGoal::startBuilder() void LocalDerivationGoal::startBuilder()
{ {
if ((buildUser && buildUser->getUIDCount() != 1) if ((buildUser && buildUser->getUIDCount() != 1)
@ -1321,7 +1289,7 @@ void LocalDerivationGoal::addDependency(const StorePath & path)
Path target = chrootRootDir + worker.store.printStorePath(path); Path target = chrootRootDir + worker.store.printStorePath(path);
if (pathExists(target)) { if (pathExists(target)) {
// There is a similar debug message in doBind, so only run it in this block to not have double messages. // There is a similar debug message in bindPath, so only run it in this block to not have double messages.
debug("bind-mounting %s -> %s", target, source); debug("bind-mounting %s -> %s", target, source);
throw Error("store path '%s' already exists in the sandbox", worker.store.printStorePath(path)); throw Error("store path '%s' already exists in the sandbox", worker.store.printStorePath(path));
} }
@ -1338,7 +1306,7 @@ void LocalDerivationGoal::addDependency(const StorePath & path)
if (setns(sandboxMountNamespace.get(), 0) == -1) if (setns(sandboxMountNamespace.get(), 0) == -1)
throw SysError("entering sandbox mount namespace"); throw SysError("entering sandbox mount namespace");
doBind(source, target); bindPath(source, target);
_exit(0); _exit(0);
}); });
@ -2117,7 +2085,7 @@ void LocalDerivationGoal::runChild()
chmodPath(dst, 0555); chmodPath(dst, 0555);
} else } else
#endif #endif
doBind(i.second.source, chrootRootDir + i.first, i.second.optional); bindPath(i.second.source, chrootRootDir + i.first, i.second.optional);
} }
/* Bind a new instance of procfs on /proc. */ /* Bind a new instance of procfs on /proc. */
@ -2156,8 +2124,8 @@ void LocalDerivationGoal::runChild()
} else { } else {
if (errno != EINVAL) if (errno != EINVAL)
throw SysError("mounting /dev/pts"); throw SysError("mounting /dev/pts");
doBind("/dev/pts", chrootRootDir + "/dev/pts"); bindPath("/dev/pts", chrootRootDir + "/dev/pts");
doBind("/dev/ptmx", chrootRootDir + "/dev/ptmx"); bindPath("/dev/ptmx", chrootRootDir + "/dev/ptmx");
} }
} }

View file

@ -21,6 +21,7 @@ libutil_sources = files(
'hilite.cc', 'hilite.cc',
'json-utils.cc', 'json-utils.cc',
'logging.cc', 'logging.cc',
'mount.cc',
'namespaces.cc', 'namespaces.cc',
'position.cc', 'position.cc',
'print-elided.cc', 'print-elided.cc',
@ -84,6 +85,7 @@ libutil_headers = files(
'logging-json.hh', 'logging-json.hh',
'lru-cache.hh', 'lru-cache.hh',
'monitor-fd.hh', 'monitor-fd.hh',
'mount.hh',
'namespaces.hh', 'namespaces.hh',
'pool.hh', 'pool.hh',
'position.hh', 'position.hh',

43
src/libutil/mount.cc Normal file
View file

@ -0,0 +1,43 @@
#include "mount.hh"
#include "error.hh"
#include "file-system.hh"
#include "logging.hh"
#if __linux__
#include <sys/mount.h>
namespace nix {
void bindPath(const Path & source, const Path & target, bool optional) {
debug("bind mounting '%1%' to '%2%'", source, target);
auto bindMount = [&]() {
if (mount(source.c_str(), target.c_str(), "", MS_BIND | MS_REC, 0) == -1)
throw SysError("bind mount from '%1%' to '%2%' failed", source, target);
};
auto maybeSt = maybeLstat(source);
if (!maybeSt) {
if (optional)
return;
else
throw SysError("getting attributes of path '%1%'", source);
}
auto st = *maybeSt;
if (S_ISDIR(st.st_mode)) {
createDirs(target);
bindMount();
} else if (S_ISLNK(st.st_mode)) {
// Symlinks can (apparently) not be bind-mounted, so just copy it
createDirs(dirOf(target));
copyFile(source, target, {});
} else {
createDirs(dirOf(target));
writeFile(target, "");
bindMount();
}
}
}
#endif

16
src/libutil/mount.hh Normal file
View file

@ -0,0 +1,16 @@
#pragma once
///@file
#include "types.hh"
#if __linux__
namespace nix {
/**
* Bind-mount file or directory from `source` to `destination`.
* If source does not exist this will fail unless `optional` is set
*/
void bindPath(const Path & source, const Path & target, bool optional = false);
}
#endif