diff options
author | Reepca Russelstein <reepca@russelstein.xyz> | 2025-07-01 12:50:06 -0500 |
---|---|---|
committer | Ludovic Courtès <ludo@gnu.org> | 2025-07-04 18:41:43 +0200 |
commit | 05a669efa51df40078df3d1f98f098464dd8e739 (patch) | |
tree | 74f42b4fa9a752b8af75813ef4fabec9de8ca08a /nix/libutil | |
parent | 6b42df3ad65e4aadb4e848eed8f36eea1974391a (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.cc | 25 |
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 |