From 4d8f7895e451df7c627208693896b356bac693e9 Mon Sep 17 00:00:00 2001 From: Stephen J Day Date: Wed, 6 Sep 2017 11:00:08 -0700 Subject: [PATCH] Revert "rootfs: remove unused functions" This reverts commit 4e2337794c2624278f1e7fa83c456fbc5b48fee5. Signed-off-by: Stephen J Day --- rootfs/init.go | 99 +++++++++++++++++++++++++++++++++++++ rootfs/init_linux.go | 114 +++++++++++++++++++++++++++++++++++++++++++ rootfs/init_other.go | 7 +++ 3 files changed, 220 insertions(+) create mode 100644 rootfs/init.go create mode 100644 rootfs/init_linux.go create mode 100644 rootfs/init_other.go diff --git a/rootfs/init.go b/rootfs/init.go new file mode 100644 index 000000000..ae3870efe --- /dev/null +++ b/rootfs/init.go @@ -0,0 +1,99 @@ +package rootfs + +import ( + "context" + "fmt" + "io/ioutil" + "os" + + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/snapshot" + digest "github.com/opencontainers/go-digest" + "github.com/pkg/errors" +) + +var ( + initializers = map[string]initializerFunc{} +) + +type initializerFunc func(string) error + +type Mounter interface { + Mount(target string, mounts ...mount.Mount) error + Unmount(target string) error +} + +func InitRootFS(ctx context.Context, name string, parent digest.Digest, readonly bool, snapshotter snapshot.Snapshotter, mounter Mounter) ([]mount.Mount, error) { + _, err := snapshotter.Stat(ctx, name) + if err == nil { + return nil, errors.Errorf("rootfs already exists") + } + // TODO: ensure not exist error once added to snapshot package + + parentS := parent.String() + + initName := defaultInitializer + initFn := initializers[initName] + if initFn != nil { + parentS, err = createInitLayer(ctx, parentS, initName, initFn, snapshotter, mounter) + if err != nil { + return nil, err + } + } + + if readonly { + return snapshotter.View(ctx, name, parentS) + } + + return snapshotter.Prepare(ctx, name, parentS) +} + +func createInitLayer(ctx context.Context, parent, initName string, initFn func(string) error, snapshotter snapshot.Snapshotter, mounter Mounter) (string, error) { + initS := fmt.Sprintf("%s %s", parent, initName) + if _, err := snapshotter.Stat(ctx, initS); err == nil { + return initS, nil + } + // TODO: ensure not exist error once added to snapshot package + + // Create tempdir + td, err := ioutil.TempDir("", "create-init-") + if err != nil { + return "", err + } + defer os.RemoveAll(td) + + mounts, err := snapshotter.Prepare(ctx, td, parent) + if err != nil { + return "", err + } + defer func() { + if err != nil { + // TODO: once implemented uncomment + //if rerr := snapshotter.Remove(ctx, td); rerr != nil { + // log.G(ctx).Errorf("Failed to remove snapshot %s: %v", td, merr) + //} + } + }() + + if err = mounter.Mount(td, mounts...); err != nil { + return "", err + } + + if err = initFn(td); err != nil { + if merr := mounter.Unmount(td); merr != nil { + log.G(ctx).Errorf("Failed to unmount %s: %v", td, merr) + } + return "", err + } + + if err = mounter.Unmount(td); err != nil { + return "", err + } + + if err := snapshotter.Commit(ctx, initS, td); err != nil { + return "", err + } + + return initS, nil +} diff --git a/rootfs/init_linux.go b/rootfs/init_linux.go new file mode 100644 index 000000000..cabc4577e --- /dev/null +++ b/rootfs/init_linux.go @@ -0,0 +1,114 @@ +package rootfs + +import ( + "os" + "path/filepath" + "syscall" +) + +const ( + defaultInitializer = "linux-init" +) + +func init() { + initializers[defaultInitializer] = initFS +} + +func createDirectory(name string, uid, gid int) initializerFunc { + return func(root string) error { + dname := filepath.Join(root, name) + st, err := os.Stat(dname) + if err != nil && !os.IsNotExist(err) { + return err + } else if err == nil { + if st.IsDir() { + stat := st.Sys().(*syscall.Stat_t) + if int(stat.Gid) == gid && int(stat.Uid) == uid { + return nil + } + } else { + if err := os.Remove(dname); err != nil { + return err + } + if err := os.Mkdir(dname, 0755); err != nil { + return err + } + } + } else { + if err := os.Mkdir(dname, 0755); err != nil { + return err + } + } + + return os.Chown(dname, uid, gid) + } +} + +func touchFile(name string, uid, gid int) initializerFunc { + return func(root string) error { + fname := filepath.Join(root, name) + + st, err := os.Stat(fname) + if err != nil && !os.IsNotExist(err) { + return err + } else if err == nil { + stat := st.Sys().(*syscall.Stat_t) + if int(stat.Gid) == gid && int(stat.Uid) == uid { + return nil + } + return os.Chown(fname, uid, gid) + } + + f, err := os.OpenFile(fname, os.O_CREATE, 0644) + if err != nil { + return err + } + defer f.Close() + + return f.Chown(uid, gid) + } +} + +func symlink(oldname, newname string) initializerFunc { + return func(root string) error { + linkName := filepath.Join(root, newname) + if _, err := os.Stat(linkName); err != nil && !os.IsNotExist(err) { + return err + } else if err == nil { + return nil + } + return os.Symlink(oldname, linkName) + } +} + +func initFS(root string) error { + st, err := os.Stat(root) + if err != nil { + return err + } + stat := st.Sys().(*syscall.Stat_t) + uid := int(stat.Uid) + gid := int(stat.Gid) + + initFuncs := []initializerFunc{ + createDirectory("/dev", uid, gid), + createDirectory("/dev/pts", uid, gid), + createDirectory("/dev/shm", uid, gid), + touchFile("/dev/console", uid, gid), + createDirectory("/proc", uid, gid), + createDirectory("/sys", uid, gid), + createDirectory("/etc", uid, gid), + touchFile("/etc/resolv.conf", uid, gid), + touchFile("/etc/hosts", uid, gid), + touchFile("/etc/hostname", uid, gid), + symlink("/proc/mounts", "/etc/mtab"), + } + + for _, fn := range initFuncs { + if err := fn(root); err != nil { + return err + } + } + + return nil +} diff --git a/rootfs/init_other.go b/rootfs/init_other.go new file mode 100644 index 000000000..b5e04e2e6 --- /dev/null +++ b/rootfs/init_other.go @@ -0,0 +1,7 @@ +// +build !linux + +package rootfs + +const ( + defaultInitializer = "" +)