[lxc-devel] [distrobuilder/master] distrobuilder: fix and restructure chroot code
monstermunchkin on Github
lxc-bot at linuxcontainers.org
Mon Feb 12 11:06:06 UTC 2018
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 362 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180212/d59c28d7/attachment.bin>
-------------- next part --------------
From f89cebdc882a1d62a0614c02e5505ff5c80af31b Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Thu, 8 Feb 2018 15:38:53 +0100
Subject: [PATCH] distrobuilder: fix and restructure chroot code
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
distrobuilder/chroot.go | 138 +++++++++++++++++++++++++++++++-----------------
distrobuilder/main.go | 14 +++--
2 files changed, 100 insertions(+), 52 deletions(-)
diff --git a/distrobuilder/chroot.go b/distrobuilder/chroot.go
index 02d11ec..f0be5b7 100644
--- a/distrobuilder/chroot.go
+++ b/distrobuilder/chroot.go
@@ -4,80 +4,124 @@ import (
"fmt"
"os"
"path/filepath"
+ "regexp"
+ "strconv"
"syscall"
"github.com/lxc/distrobuilder/managers"
"github.com/lxc/distrobuilder/shared"
)
-func prepareChroot(cacheDir string) ([]string, error) {
- type Mount struct {
- source string
- target string
- fstype string
- flags uintptr
- data string
+type chrootMount struct {
+ source string
+ target string
+ fstype string
+ flags uintptr
+ data string
+ remove bool
+ mounted bool
+ isDir bool
+}
+
+func mountFilesystems(rootfs string, mounts []chrootMount) bool {
+ ok := true
+
+ for i, mount := range mounts {
+ if mount.isDir {
+ os.MkdirAll(filepath.Join(rootfs, mount.target), 0755)
+ } else {
+ os.Create(filepath.Join(rootfs, mount.target))
+ }
+ err := syscall.Mount(mount.source, filepath.Join(rootfs, mount.target),
+ mount.fstype, mount.flags, mount.data)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to mount '%s': %s\n", mount.source, err)
+ ok = false
+ break
+ }
+ mounts[i].mounted = true
}
- var (
- err error
- unmounts []string
- )
+ return ok
+}
- mounts := []Mount{
- {filepath.Join(cacheDir, "rootfs"), "", "tmpfs", syscall.MS_BIND, ""},
- {"proc", "proc", "proc", 0, ""},
- {"sys", "sys", "sysfs", 0, ""},
- {"udev", "dev", "devtmpfs", 0, ""},
- {"shm", "/dev/shm", "tmpfs", 0, ""},
- {"/dev/pts", "/dev/pts", "tmpfs", syscall.MS_BIND, ""},
- {"run", "/run", "tmpfs", 0, ""},
- {"tmp", "/tmp", "tmpfs", 0, ""},
+func unmountFilesystems(rootfs string, mounts []chrootMount) {
+ // unmount targets in reversed order
+ for i := len(mounts) - 1; i >= 0; i-- {
+ if mounts[i].mounted {
+ err := syscall.Unmount(filepath.Join(rootfs, mounts[i].target), 0)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to unmount '%s': %s\n", mounts[i].target, err)
+ continue
+ }
+ mounts[i].mounted = false
+
+ if mounts[i].remove {
+ os.RemoveAll(filepath.Join(rootfs, mounts[i].target))
+ }
+ }
}
+}
- os.MkdirAll(filepath.Join(cacheDir, "rootfs", "dev", "pts"), 0755)
+func killChrootProcesses(rootfs string) error {
+ proc, err := os.Open(filepath.Join(rootfs, "proc"))
+ if err != nil {
+ return err
+ }
- for _, mount := range mounts {
- err = syscall.Mount(mount.source, filepath.Join(cacheDir, "rootfs", mount.target),
- mount.fstype, mount.flags, mount.data)
- if err != nil {
- return unmounts, err
+ dirs, err := proc.Readdirnames(0)
+ if err != nil {
+ return err
+ }
+
+ for _, dir := range dirs {
+ match, _ := regexp.MatchString(`\d+`, dir)
+ if match {
+ link, _ := os.Readlink(filepath.Join(rootfs, "proc", dir, "root"))
+ if link == rootfs {
+ pid, _ := strconv.Atoi(dir)
+ syscall.Kill(pid, syscall.SIGKILL)
+ }
}
- unmounts = append(unmounts, filepath.Join(cacheDir, "rootfs", mount.target))
}
- return unmounts, nil
+ return nil
}
-func setupChroot(cacheDir string) (func() error, error) {
+func setupChroot(rootfs string) (func() error, error) {
var err error
- cwd, err := os.Getwd()
- if err != nil {
- return nil, err
+ mounts := []chrootMount{
+ {rootfs, "", "tmpfs", syscall.MS_BIND, "", false, false, true},
+ {"proc", "proc", "proc", 0, "", false, false, true},
+ {"sys", "sys", "sysfs", 0, "", false, false, true},
+ {"udev", "dev", "devtmpfs", 0, "", false, false, true},
+ {"shm", "/dev/shm", "tmpfs", 0, "", true, false, true},
+ {"/dev/pts", "/dev/pts", "tmpfs", syscall.MS_BIND, "", true, false, true},
+ {"run", "/run", "tmpfs", 0, "", false, false, true},
+ {"tmp", "/tmp", "tmpfs", 0, "", false, false, true},
+ {"/etc/resolv.conf", "/etc/resolv.conf", "", syscall.MS_BIND, "", false, false, false},
}
- err = shared.Copy("/etc/resolv.conf", filepath.Join(cacheDir, "rootfs", "etc", "resolv.conf"))
+ cwd, err := os.Getwd()
if err != nil {
return nil, err
}
- unmounts, err := prepareChroot(cacheDir)
- if err != nil {
- for i := len(unmounts) - 1; i >= 0; i-- {
- syscall.Unmount(unmounts[i], 0)
- }
- return nil, err
+ ok := mountFilesystems(rootfs, mounts)
+ if !ok {
+ unmountFilesystems(rootfs, mounts)
+ return nil, fmt.Errorf("Failed to mount filesystems")
}
- syscall.Mknod(filepath.Join(cacheDir, "rootfs", "dev", "null"), 1, 3)
+ syscall.Mknod(filepath.Join(rootfs, "dev", "null"), 1, 3)
root, err := os.Open("/")
if err != nil {
return nil, err
}
- err = syscall.Chroot(filepath.Join(cacheDir, "rootfs"))
+ err = syscall.Chroot(rootfs)
if err != nil {
root.Close()
return nil, err
@@ -89,11 +133,6 @@ func setupChroot(cacheDir string) (func() error, error) {
}
return func() error {
- // unmount targets in reversed order
- for i := len(unmounts) - 1; i >= 0; i-- {
- syscall.Unmount(unmounts[i], 0)
- }
-
defer root.Close()
err = root.Chdir()
@@ -111,11 +150,16 @@ func setupChroot(cacheDir string) (func() error, error) {
return err
}
+ // This will kill all processes in the chroot and allow to cleanly
+ // unmount everything.
+ killChrootProcesses(rootfs)
+ unmountFilesystems(rootfs, mounts)
+
return nil
}, nil
}
-func manageChroot(def shared.DefinitionPackages) error {
+func managePackages(def shared.DefinitionPackages) error {
var err error
manager := managers.Get(def.Manager)
diff --git a/distrobuilder/main.go b/distrobuilder/main.go
index c8187a4..f9fa2f4 100644
--- a/distrobuilder/main.go
+++ b/distrobuilder/main.go
@@ -52,6 +52,7 @@ import (
"fmt"
"io"
"os"
+ "path/filepath"
"github.com/lxc/distrobuilder/shared"
"github.com/lxc/distrobuilder/sources"
@@ -151,17 +152,20 @@ func run(c *cli.Context) error {
defer os.RemoveAll(c.GlobalString("cache-dir"))
}
- exitFunc, err := setupChroot(c.GlobalString("cache-dir"))
+ // enter chroot
+ exitChroot, err := setupChroot(filepath.Join(c.GlobalString("cache-dir"), "rootfs"))
if err != nil {
- return fmt.Errorf("Failed to chroot: %s", err)
+ return fmt.Errorf("Failed to setup chroot: %s", err)
}
- defer exitFunc()
- err = manageChroot(def.Packages)
+ err = managePackages(def.Packages)
if err != nil {
- return fmt.Errorf("Failed to run setup: %s", err)
+ exitChroot()
+ return fmt.Errorf("Failed to manage packages: %s", err)
}
+ exitChroot()
+
return nil
}
More information about the lxc-devel
mailing list