summaryrefslogtreecommitdiff
path: root/nix/libutil
diff options
context:
space:
mode:
authorReepca Russelstein <reepca@russelstein.xyz>2025-07-01 12:50:06 -0500
committerLudovic Courtès <ludo@gnu.org>2025-07-04 18:41:43 +0200
commit05a669efa51df40078df3d1f98f098464dd8e739 (patch)
tree74f42b4fa9a752b8af75813ef4fabec9de8ca08a /nix/libutil
parent6b42df3ad65e4aadb4e848eed8f36eea1974391a (diff)
daemon: Gracefully handle target mount point already existing.
Fixes guix/guix#903. * nix/libutil/spawn.cc (bindMount): in the "regular file" case, only create a placeholder file if one doesn't already exist. Change-Id: Ie46b2fef2cea5b2a052c4ec48d00e97bfc1ee506 Reported-by: Hilton Chain <hako@ultrarare.space> Signed-off-by: Ludovic Courtès <ludo@gnu.org>
Diffstat (limited to 'nix/libutil')
-rw-r--r--nix/libutil/spawn.cc25
1 files changed, 24 insertions, 1 deletions
diff --git a/nix/libutil/spawn.cc b/nix/libutil/spawn.cc
index 2e3e1ac1a7..d3f4e5bf19 100644
--- a/nix/libutil/spawn.cc
+++ b/nix/libutil/spawn.cc
@@ -538,8 +538,31 @@ void bindMount(Path source, Path target, bool readOnly)
return;
}
else {
+ struct stat st2;
createDirs(dirOf(target));
- writeFile(target, "");
+ /* Alternate between trying to create placeholder file at target and
+ * checking for its existence and type */
+ while(true){
+ if(lstat(target.c_str(), &st2) != -1) {
+ if(!S_ISREG(st2.st_mode))
+ throw Error(format("mount target `%1%' exists but is not a regular file") % target);
+ break;
+ }
+ if(errno != ENOENT) {
+ throw SysError(format("stat'ing path `%1%'") % target);
+ }
+ AutoCloseFD fd = open(target.c_str(),
+ O_WRONLY | O_NOFOLLOW | O_CREAT | O_EXCL,
+ 0600);
+ if(fd != -1) {
+ fd.close(); /* Now exists and is a fresh regular file */
+ break;
+ }
+ /* Note: because of O_CREAT | O_EXCL, EACCES can only mean a
+ * permission issue with the parent directory */
+ if(errno != EEXIST)
+ throw SysError(format("Creating placeholder regular file target mount `%1%'") % target);
+ }
}
/* This may fail with EINVAL unless we specify MS_REC, specifically if we