summary refs log tree commit diff
path: root/nixos/modules/virtualisation
diff options
context:
space:
mode:
authoraszlig <aszlig@redmoonstudios.org>2014-09-11 18:03:45 +0200
committeraszlig <aszlig@redmoonstudios.org>2014-09-11 18:12:35 +0200
commitd394d095ab6dc32f1ee45c75e51b56ca9a443548 (patch)
tree28503454c235b391081c8ce8cbc5455e945519d5 /nixos/modules/virtualisation
parent859f049d1b813e71dfb17ffd8e5189d2964d122d (diff)
downloadnixlib-d394d095ab6dc32f1ee45c75e51b56ca9a443548.tar
nixlib-d394d095ab6dc32f1ee45c75e51b56ca9a443548.tar.gz
nixlib-d394d095ab6dc32f1ee45c75e51b56ca9a443548.tar.bz2
nixlib-d394d095ab6dc32f1ee45c75e51b56ca9a443548.tar.lz
nixlib-d394d095ab6dc32f1ee45c75e51b56ca9a443548.tar.xz
nixlib-d394d095ab6dc32f1ee45c75e51b56ca9a443548.tar.zst
nixlib-d394d095ab6dc32f1ee45c75e51b56ca9a443548.zip
containers: Don't descend into mounts on destroy.
This tells the sad tale of @the-kenny who had bind-mounted his home
directory into a container. After doing `nixos-container destroy` he
discovered that his home directory went from "full of precious data" to
"no more data".

We want to avoid having similar sad tales in the future, so this now also
check this in the containers VM test.

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
Diffstat (limited to 'nixos/modules/virtualisation')
-rw-r--r--nixos/modules/virtualisation/nixos-container.pl23
1 files changed, 20 insertions, 3 deletions
diff --git a/nixos/modules/virtualisation/nixos-container.pl b/nixos/modules/virtualisation/nixos-container.pl
index 7403a42f0f14..9ae5331786cc 100644
--- a/nixos/modules/virtualisation/nixos-container.pl
+++ b/nixos/modules/virtualisation/nixos-container.pl
@@ -201,15 +201,32 @@ sub runInContainer {
     die "cannot run ‘nsenter’: $!\n";
 }
 
+# Remove a directory while recursively unmounting all mounted filesystems within
+# that directory and unmounting/removing that directory afterwards as well.
+#
+# NOTE: If the specified path is a mountpoint, its contents will be removed,
+#       only mountpoints underneath that path will be unmounted properly.
+sub safeRemoveTree {
+    my ($path) = @_;
+    system("find", $path, "-mindepth", "1", "-xdev",
+           "(", "-type", "d", "-exec", "mountpoint", "-q", "{}", ";", ")",
+           "-exec", "umount", "-fR", "{}", "+");
+    system("rm", "--one-file-system", "-rf", $path);
+    if (-e $path) {
+        system("umount", "-fR", $path);
+        system("rm", "--one-file-system", "-rf", $path);
+    }
+}
+
 if ($action eq "destroy") {
     die "$0: cannot destroy declarative container (remove it from your configuration.nix instead)\n"
         unless POSIX::access($confFile, &POSIX::W_OK);
 
     stopContainer if isContainerRunning;
 
-    rmtree($profileDir) if -e $profileDir;
-    rmtree($gcRootsDir) if -e $gcRootsDir;
-    rmtree($root) if -e $root;
+    safeRemoveTree($profileDir) if -e $profileDir;
+    safeRemoveTree($gcRootsDir) if -e $gcRootsDir;
+    safeRemoveTree($root) if -e $root;
     unlink($confFile) or die;
 }