The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/distrobuilder/pull/18

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
Signed-off-by: Stéphane Graber <[email protected]>
From 3ed3b15cf7951948b7b8a7e335e4c9c68b236481 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <[email protected]>
Date: Wed, 21 Feb 2018 13:31:48 -0500
Subject: [PATCH] chroot: Fix mount logic and symlink handling
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <[email protected]>
---
 distrobuilder/chroot.go | 74 +++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 63 insertions(+), 11 deletions(-)

diff --git a/distrobuilder/chroot.go b/distrobuilder/chroot.go
index f055d73..f859dcb 100644
--- a/distrobuilder/chroot.go
+++ b/distrobuilder/chroot.go
@@ -22,15 +22,19 @@ type chrootMount struct {
 }
 
 func setupMounts(rootfs string, mounts []chrootMount) error {
+       // Create a temporary mount path
        err := os.MkdirAll(filepath.Join(rootfs, ".distrobuilder"), 0700)
        if err != nil {
                return err
        }
 
        for i, mount := range mounts {
+               // Target path
                tmpTarget := filepath.Join(rootfs, ".distrobuilder", 
fmt.Sprintf("%d", i))
+
+               // Create the target mountpoint
                if mount.isDir {
-                       err := os.MkdirAll(tmpTarget, 0755)
+                       err := os.Mkdir(tmpTarget, 0755)
                        if err != nil {
                                return err
                        }
@@ -41,6 +45,7 @@ func setupMounts(rootfs string, mounts []chrootMount) error {
                        }
                }
 
+               // Mount to the temporary path
                err := syscall.Mount(mount.source, tmpTarget, mount.fstype, 
mount.flags, mount.data)
                if err != nil {
                        return fmt.Errorf("Failed to mount '%s': %s", 
mount.source, err)
@@ -52,25 +57,59 @@ func setupMounts(rootfs string, mounts []chrootMount) error 
{
 
 func moveMounts(mounts []chrootMount) error {
        for i, mount := range mounts {
+               // Source path
                tmpSource := filepath.Join("/", ".distrobuilder", 
fmt.Sprintf("%d", i))
+
+               // Resolve symlinks
+               target := mount.target
+               for {
+                       // Get information on current target
+                       fi, err := os.Lstat(target)
+                       if err != nil {
+                               break
+                       }
+
+                       // If not a symlink, we're done
+                       if fi.Mode()&os.ModeSymlink == 0 {
+                               break
+                       }
+
+                       // If a symlink, resolve it
+                       newTarget, err := os.Readlink(target)
+                       if err != nil {
+                               break
+                       }
+
+                       target = newTarget
+               }
+
+               // Create parent paths if missing
+               err := os.MkdirAll(filepath.Dir(target), 0755)
+               if err != nil {
+                       return err
+               }
+
+               // Create target path
                if mount.isDir {
-                       err := os.MkdirAll(mount.target, 0755)
+                       err = os.MkdirAll(target, 0755)
                        if err != nil {
                                return err
                        }
                } else {
-                       _, err := os.Create(mount.target)
+                       _, err = os.Create(target)
                        if err != nil {
                                return err
                        }
                }
 
-               err := syscall.Mount(tmpSource, mount.target, "", 
syscall.MS_MOVE, "")
+               // Move the mount to its destination
+               err = syscall.Mount(tmpSource, target, "", syscall.MS_MOVE, "")
                if err != nil {
                        return fmt.Errorf("Failed to mount '%s': %s", 
mount.source, err)
                }
        }
 
+       // Cleanup our temporary path
        err := os.RemoveAll(filepath.Join("/", ".distrobuilder"))
        if err != nil {
                return err
@@ -81,6 +120,7 @@ func moveMounts(mounts []chrootMount) error {
 }
 
 func killChrootProcesses(rootfs string) error {
+       // List all files under /proc
        proc, err := os.Open(filepath.Join(rootfs, "proc"))
        if err != nil {
                return err
@@ -91,6 +131,7 @@ func killChrootProcesses(rootfs string) error {
                return err
        }
 
+       // Get all processes and kill them
        for _, dir := range dirs {
                match, _ := regexp.MatchString(`\d+`, dir)
                if match {
@@ -106,10 +147,14 @@ func killChrootProcesses(rootfs string) error {
 }
 
 func setupChroot(rootfs string) (func() error, error) {
-       var err error
+       // Mount the rootfs
+       err := syscall.Mount(rootfs, rootfs, "", syscall.MS_BIND, "")
+       if err != nil {
+               return nil, fmt.Errorf("Failed to mount '%s': %s", rootfs, err)
+       }
 
+       // Setup all other needed mounts
        mounts := []chrootMount{
-               {rootfs, "/", "", syscall.MS_BIND, "", true},
                {"none", "/proc", "proc", 0, "", true},
                {"none", "/sys", "sysfs", 0, "", true},
                {"/dev", "/dev", "", syscall.MS_BIND, "", true},
@@ -118,21 +163,24 @@ func setupChroot(rootfs string) (func() error, error) {
                {"/etc/resolv.conf", "/etc/resolv.conf", "", syscall.MS_BIND, 
"", false},
        }
 
-       cwd, err := os.Getwd()
+       // Keep a reference to the host rootfs and cwd
+       root, err := os.Open("/")
        if err != nil {
                return nil, err
        }
 
-       err = setupMounts(rootfs, mounts)
+       cwd, err := os.Getwd()
        if err != nil {
-               return nil, fmt.Errorf("Failed to mount filesystems: %v", err)
+               return nil, err
        }
 
-       root, err := os.Open("/")
+       // Setup all needed mounts in a temporary location
+       err = setupMounts(rootfs, mounts)
        if err != nil {
-               return nil, err
+               return nil, fmt.Errorf("Failed to mount filesystems: %v", err)
        }
 
+       // Chroot into the container's rootfs
        err = syscall.Chroot(rootfs)
        if err != nil {
                root.Close()
@@ -144,6 +192,7 @@ func setupChroot(rootfs string) (func() error, error) {
                return nil, err
        }
 
+       // Move all the mounts into place
        err = moveMounts(mounts)
        if err != nil {
                return nil, err
@@ -152,6 +201,7 @@ func setupChroot(rootfs string) (func() error, error) {
        return func() error {
                defer root.Close()
 
+               // Switch back to the host rootfs
                err = root.Chdir()
                if err != nil {
                        return err
@@ -170,6 +220,8 @@ func setupChroot(rootfs string) (func() error, error) {
                // This will kill all processes in the chroot and allow to 
cleanly
                // unmount everything.
                killChrootProcesses(rootfs)
+
+               // And now unmount the entire tree
                syscall.Unmount(rootfs, syscall.MNT_DETACH)
 
                return nil
_______________________________________________
lxc-devel mailing list
[email protected]
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to