1// +build linux freebsd
2
3package initlayer // import "github.com/docker/docker/daemon/initlayer"
4
5import (
6	"os"
7	"path/filepath"
8	"strings"
9
10	"github.com/docker/docker/pkg/containerfs"
11	"github.com/docker/docker/pkg/idtools"
12	"golang.org/x/sys/unix"
13)
14
15// Setup populates a directory with mountpoints suitable
16// for bind-mounting things into the container.
17//
18// This extra layer is used by all containers as the top-most ro layer. It protects
19// the container from unwanted side-effects on the rw layer.
20func Setup(initLayerFs containerfs.ContainerFS, rootIdentity idtools.Identity) error {
21	// Since all paths are local to the container, we can just extract initLayerFs.Path()
22	initLayer := initLayerFs.Path()
23
24	for pth, typ := range map[string]string{
25		"/dev/pts":         "dir",
26		"/dev/shm":         "dir",
27		"/proc":            "dir",
28		"/sys":             "dir",
29		"/.dockerenv":      "file",
30		"/etc/resolv.conf": "file",
31		"/etc/hosts":       "file",
32		"/etc/hostname":    "file",
33		"/dev/console":     "file",
34		"/etc/mtab":        "/proc/mounts",
35	} {
36		parts := strings.Split(pth, "/")
37		prev := "/"
38		for _, p := range parts[1:] {
39			prev = filepath.Join(prev, p)
40			unix.Unlink(filepath.Join(initLayer, prev))
41		}
42
43		if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil {
44			if os.IsNotExist(err) {
45				if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootIdentity); err != nil {
46					return err
47				}
48				switch typ {
49				case "dir":
50					if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, pth), 0755, rootIdentity); err != nil {
51						return err
52					}
53				case "file":
54					f, err := os.OpenFile(filepath.Join(initLayer, pth), os.O_CREATE, 0755)
55					if err != nil {
56						return err
57					}
58					f.Chown(rootIdentity.UID, rootIdentity.GID)
59					f.Close()
60				default:
61					if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil {
62						return err
63					}
64				}
65			} else {
66				return err
67			}
68		}
69	}
70
71	// Layer is ready to use, if it wasn't before.
72	return nil
73}
74