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 | |
| 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>
| -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 2e3e1ac1a79..d3f4e5bf19a 100644 --- a/nix/libutil/spawn.cc +++ b/nix/libutil/spawn.cc | |||
| @@ -538,8 +538,31 @@ void bindMount(Path source, Path target, bool readOnly) | |||
| 538 | return; | 538 | return; |
| 539 | } | 539 | } |
| 540 | else { | 540 | else { |
| 541 | struct stat st2; | ||
| 541 | createDirs(dirOf(target)); | 542 | createDirs(dirOf(target)); |
| 542 | writeFile(target, ""); | 543 | /* Alternate between trying to create placeholder file at target and |
| 544 | * checking for its existence and type */ | ||
| 545 | while(true){ | ||
| 546 | if(lstat(target.c_str(), &st2) != -1) { | ||
| 547 | if(!S_ISREG(st2.st_mode)) | ||
| 548 | throw Error(format("mount target `%1%' exists but is not a regular file") % target); | ||
| 549 | break; | ||
| 550 | } | ||
| 551 | if(errno != ENOENT) { | ||
| 552 | throw SysError(format("stat'ing path `%1%'") % target); | ||
| 553 | } | ||
| 554 | AutoCloseFD fd = open(target.c_str(), | ||
| 555 | O_WRONLY | O_NOFOLLOW | O_CREAT | O_EXCL, | ||
| 556 | 0600); | ||
| 557 | if(fd != -1) { | ||
| 558 | fd.close(); /* Now exists and is a fresh regular file */ | ||
| 559 | break; | ||
| 560 | } | ||
| 561 | /* Note: because of O_CREAT | O_EXCL, EACCES can only mean a | ||
| 562 | * permission issue with the parent directory */ | ||
| 563 | if(errno != EEXIST) | ||
| 564 | throw SysError(format("Creating placeholder regular file target mount `%1%'") % target); | ||
| 565 | } | ||
| 543 | } | 566 | } |
| 544 | 567 | ||
| 545 | /* This may fail with EINVAL unless we specify MS_REC, specifically if we | 568 | /* This may fail with EINVAL unless we specify MS_REC, specifically if we |
