Browse code

Use nsinit as app Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)

Michael Crosby authored on 2014/02/20 07:33:25
Showing 8 changed files
... ...
@@ -2,18 +2,14 @@ package libcontainer
2 2
 
3 3
 type Container struct {
4 4
 	ID           string       `json:"id,omitempty"`
5
-	NsPid        int          `json:"namespace_pid,omitempty"`
6 5
 	Command      *Command     `json:"command,omitempty"`
7
-	RootFs       string       `json:"rootfs,omitempty"`
8 6
 	ReadonlyFs   bool         `json:"readonly_fs,omitempty"`
9
-	NetNsFd      uintptr      `json:"network_namespace_fd,omitempty"`
10 7
 	User         string       `json:"user,omitempty"`
11 8
 	WorkingDir   string       `json:"working_dir,omitempty"`
12 9
 	Namespaces   Namespaces   `json:"namespaces,omitempty"`
13 10
 	Capabilities Capabilities `json:"capabilities,omitempty"`
14
-	Master       uintptr      `json:"master"`
15
-	Console      string       `json:"console"`
16
-	LogFile      string       `json:"log_file"`
11
+	LogFile      string       `json:"log_file,omitempty"`
12
+	Network      *Network     `json:"network,omitempty"`
17 13
 }
18 14
 
19 15
 type Command struct {
... ...
@@ -22,9 +18,9 @@ type Command struct {
22 22
 }
23 23
 
24 24
 type Network struct {
25
-	TempVethName string `json:"temp_veth,omitempty"`
26 25
 	IP           string `json:"ip,omitempty"`
27 26
 	Gateway      string `json:"gateway,omitempty"`
28 27
 	Bridge       string `json:"bridge,omitempty"`
29 28
 	Mtu          int    `json:"mtu,omitempty"`
29
+	TempVethName string `json:"temp_veth,omitempty"`
30 30
 }
... ...
@@ -1,27 +1,17 @@
1
-/*
2
-   Higher level convience functions for setting up a container
3
-*/
4
-
5 1
 package namespaces
6 2
 
7 3
 import (
8
-	"errors"
9 4
 	"github.com/dotcloud/docker/pkg/libcontainer"
10 5
 	"github.com/dotcloud/docker/pkg/system"
6
+	"github.com/dotcloud/docker/pkg/term"
11 7
 	"io"
12 8
 	"log"
13 9
 	"os"
14 10
 	"os/exec"
15
-	"path/filepath"
16
-	"strconv"
17 11
 	"syscall"
18 12
 )
19 13
 
20
-var (
21
-	ErrExistingNetworkNamespace = errors.New("specified both CLONE_NEWNET and an existing network namespace")
22
-)
23
-
24
-// Exec will spawn new namespaces with the specified Container configuration
14
+// ExecContainer will spawn new namespaces with the specified Container configuration
25 15
 // in the RootFs path and return the pid of the new containerized process.
26 16
 //
27 17
 // If an existing network namespace is specified the container
... ...
@@ -30,30 +20,19 @@ var (
30 30
 // existing network namespace and the CLONE_NEWNET option in the container configuration will allow
31 31
 // the container to the the host's networking options and configuration.
32 32
 func ExecContainer(container *libcontainer.Container) (pid int, err error) {
33
-	// a user cannot pass CLONE_NEWNET and an existing net namespace fd to join
34
-	if container.NetNsFd > 0 && container.Namespaces.Contains(libcontainer.CLONE_NEWNET) {
35
-		return -1, ErrExistingNetworkNamespace
36
-	}
37
-
38 33
 	master, console, err := createMasterAndConsole()
39 34
 	if err != nil {
40 35
 		return -1, err
41 36
 	}
42
-	nsinit := filepath.Join(container.RootFs, ".nsinit")
43 37
 
44 38
 	// we need CLONE_VFORK so we can wait on the child
45 39
 	flag := uintptr(getNamespaceFlags(container.Namespaces) | CLONE_VFORK)
46 40
 
47
-	command := exec.Command(nsinit, "-master", strconv.Itoa(int(master.Fd())), "-console", console, "init", "container.json")
48
-	// command.Stdin = os.Stdin
49
-	// command.Stdout = os.Stdout
50
-	// command.Stderr = os.Stderr
51
-	command.SysProcAttr = &syscall.SysProcAttr{}
52
-	command.SysProcAttr.Cloneflags = flag
53
-
54
-	command.ExtraFiles = []*os.File{master}
41
+	command := exec.Command("nsinit", console)
42
+	command.SysProcAttr = &syscall.SysProcAttr{
43
+		Cloneflags: flag,
44
+	}
55 45
 
56
-	println("vvvvvvvvv")
57 46
 	if err := command.Start(); err != nil {
58 47
 		return -1, err
59 48
 	}
... ...
@@ -64,11 +43,18 @@ func ExecContainer(container *libcontainer.Container) (pid int, err error) {
64 64
 			log.Println(err)
65 65
 		}
66 66
 	}()
67
+
67 68
 	go func() {
68 69
 		if _, err := io.Copy(master, os.Stdin); err != nil {
69 70
 			log.Println(err)
70 71
 		}
71 72
 	}()
73
+
74
+	term.SetRawTerminal(os.Stdin.Fd())
75
+
76
+	if err := command.Wait(); err != nil {
77
+		return pid, err
78
+	}
72 79
 	return pid, nil
73 80
 }
74 81
 
75 82
deleted file mode 100644
... ...
@@ -1,7 +0,0 @@
1
-// +build linux,x86_64
2
-package namespaces
3
-
4
-// Via http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=7b21fddd087678a70ad64afc0f632e0f1071b092
5
-const (
6
-	SYS_SETNS = 308
7
-)
8 1
deleted file mode 100644
... ...
@@ -1,209 +0,0 @@
1
-package namespaces
2
-
3
-import (
4
-	"fmt"
5
-	"github.com/dotcloud/docker/pkg/system"
6
-	"log"
7
-	"os"
8
-	"path/filepath"
9
-	"syscall"
10
-)
11
-
12
-var (
13
-	// default mount point options
14
-	defaults = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV
15
-)
16
-
17
-func SetupNewMountNamespace(rootfs, console string, readonly bool) error {
18
-	if err := system.Mount("", "/", "", syscall.MS_SLAVE|syscall.MS_REC, ""); err != nil {
19
-		return fmt.Errorf("mounting / as slave %s", err)
20
-	}
21
-
22
-	if err := system.Mount(rootfs, rootfs, "bind", syscall.MS_BIND|syscall.MS_REC, ""); err != nil {
23
-		return fmt.Errorf("mouting %s as bind %s", rootfs, err)
24
-	}
25
-
26
-	if readonly {
27
-		if err := system.Mount(rootfs, rootfs, "bind", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_REC, ""); err != nil {
28
-			return fmt.Errorf("mounting %s as readonly %s", rootfs, err)
29
-		}
30
-	}
31
-
32
-	if err := mountSystem(rootfs); err != nil {
33
-		return fmt.Errorf("mount system %s", err)
34
-	}
35
-
36
-	if err := copyDevNodes(rootfs); err != nil {
37
-		return fmt.Errorf("copy dev nodes %s", err)
38
-	}
39
-
40
-	ptmx := filepath.Join(rootfs, "dev/ptmx")
41
-	if err := os.Remove(ptmx); err != nil && !os.IsNotExist(err) {
42
-		return err
43
-	}
44
-	if err := os.Symlink("pts/ptmx", ptmx); err != nil {
45
-		return fmt.Errorf("symlink dev ptmx %s", err)
46
-	}
47
-
48
-	if err := setupDev(rootfs); err != nil {
49
-		return err
50
-	}
51
-
52
-	if err := setupConsole(rootfs, console); err != nil {
53
-		return err
54
-	}
55
-
56
-	if err := system.Chdir(rootfs); err != nil {
57
-		return fmt.Errorf("chdir into %s %s", rootfs, err)
58
-	}
59
-
60
-	if err := system.Mount(rootfs, "/", "", syscall.MS_MOVE, ""); err != nil {
61
-		return fmt.Errorf("mount move %s into / %s", rootfs, err)
62
-	}
63
-
64
-	if err := system.Chroot("."); err != nil {
65
-		return fmt.Errorf("chroot . %s", err)
66
-	}
67
-
68
-	if err := system.Chdir("/"); err != nil {
69
-		return fmt.Errorf("chdir / %s", err)
70
-	}
71
-
72
-	system.Umask(0022)
73
-
74
-	return nil
75
-}
76
-
77
-func copyDevNodes(rootfs string) error {
78
-	oldMask := system.Umask(0000)
79
-	defer system.Umask(oldMask)
80
-
81
-	for _, node := range []string{
82
-		"null",
83
-		"zero",
84
-		"full",
85
-		"random",
86
-		"urandom",
87
-		"tty",
88
-	} {
89
-		stat, err := os.Stat(filepath.Join("/dev", node))
90
-		if err != nil {
91
-			return err
92
-		}
93
-
94
-		var (
95
-			dest = filepath.Join(rootfs, "dev", node)
96
-			st   = stat.Sys().(*syscall.Stat_t)
97
-		)
98
-
99
-		log.Printf("copy %s to %s %d\n", node, dest, st.Rdev)
100
-		if err := system.Mknod(dest, st.Mode, int(st.Rdev)); err != nil && !os.IsExist(err) {
101
-			return fmt.Errorf("copy %s %s", node, err)
102
-		}
103
-	}
104
-	return nil
105
-}
106
-
107
-func setupDev(rootfs string) error {
108
-	for _, link := range []struct {
109
-		from string
110
-		to   string
111
-	}{
112
-		{"/proc/kcore", "/dev/core"},
113
-		{"/proc/self/fd", "/dev/fd"},
114
-		{"/proc/self/fd/0", "/dev/stdin"},
115
-		{"/proc/self/fd/1", "/dev/stdout"},
116
-		{"/proc/self/fd/2", "/dev/stderr"},
117
-	} {
118
-		dest := filepath.Join(rootfs, link.to)
119
-		if err := os.Remove(dest); err != nil && !os.IsNotExist(err) {
120
-			return fmt.Errorf("remove %s %s", dest, err)
121
-		}
122
-		if err := os.Symlink(link.from, dest); err != nil {
123
-			return fmt.Errorf("symlink %s %s", dest, err)
124
-		}
125
-	}
126
-	return nil
127
-}
128
-
129
-func setupConsole(rootfs, console string) error {
130
-	oldMask := system.Umask(0000)
131
-	defer system.Umask(oldMask)
132
-
133
-	stat, err := os.Stat(console)
134
-	if err != nil {
135
-		return fmt.Errorf("stat console %s %s", console, err)
136
-	}
137
-	st := stat.Sys().(*syscall.Stat_t)
138
-
139
-	dest := filepath.Join(rootfs, "dev/console")
140
-	if err := os.Remove(dest); err != nil && !os.IsNotExist(err) {
141
-		return fmt.Errorf("remove %s %s", dest, err)
142
-	}
143
-
144
-	if err := os.Chmod(console, 0600); err != nil {
145
-		return err
146
-	}
147
-	if err := os.Chown(console, 0, 0); err != nil {
148
-		return err
149
-	}
150
-
151
-	if err := system.Mknod(dest, (st.Mode&^07777)|0600, int(st.Rdev)); err != nil {
152
-		return fmt.Errorf("mknod %s %s", dest, err)
153
-	}
154
-
155
-	if err := system.Mount(console, dest, "bind", syscall.MS_BIND, ""); err != nil {
156
-		return fmt.Errorf("bind %s to %s %s", console, dest, err)
157
-	}
158
-	return nil
159
-}
160
-
161
-// mountSystem sets up linux specific system mounts like sys, proc, shm, and devpts
162
-// inside the mount namespace
163
-func mountSystem(rootfs string) error {
164
-	for _, m := range []struct {
165
-		source string
166
-		path   string
167
-		device string
168
-		flags  int
169
-		data   string
170
-	}{
171
-		{source: "proc", path: filepath.Join(rootfs, "proc"), device: "proc", flags: defaults},
172
-		{source: "sysfs", path: filepath.Join(rootfs, "sys"), device: "sysfs", flags: defaults},
173
-		{source: "tmpfs", path: filepath.Join(rootfs, "dev"), device: "tmpfs", flags: syscall.MS_NOSUID | syscall.MS_STRICTATIME, data: "mode=755"},
174
-		{source: "shm", path: filepath.Join(rootfs, "dev", "shm"), device: "tmpfs", flags: defaults, data: "mode=1777"},
175
-		{source: "devpts", path: filepath.Join(rootfs, "dev", "pts"), device: "devpts", flags: syscall.MS_NOSUID | syscall.MS_NOEXEC, data: "newinstance,ptmxmode=0666,mode=620,gid=5"},
176
-		{source: "tmpfs", path: filepath.Join(rootfs, "run"), device: "tmpfs", flags: syscall.MS_NOSUID | syscall.MS_NODEV | syscall.MS_STRICTATIME, data: "mode=755"},
177
-	} {
178
-		if err := os.MkdirAll(m.path, 0755); err != nil && !os.IsExist(err) {
179
-			return fmt.Errorf("mkdirall %s %s", m.path, err)
180
-		}
181
-		if err := system.Mount(m.source, m.path, m.device, uintptr(m.flags), m.data); err != nil {
182
-			return fmt.Errorf("mounting %s into %s %s", m.source, m.path, err)
183
-		}
184
-	}
185
-	return nil
186
-}
187
-
188
-func remountProc() error {
189
-	if err := system.Unmount("/proc", syscall.MNT_DETACH); err != nil {
190
-		return err
191
-	}
192
-	if err := system.Mount("proc", "/proc", "proc", uintptr(defaults), ""); err != nil {
193
-		return err
194
-	}
195
-	return nil
196
-}
197
-
198
-func remountSys() error {
199
-	if err := system.Unmount("/sys", syscall.MNT_DETACH); err != nil {
200
-		if err != syscall.EINVAL {
201
-			return err
202
-		}
203
-	} else {
204
-		if err := system.Mount("sysfs", "/sys", "sysfs", uintptr(defaults), ""); err != nil {
205
-			return err
206
-		}
207
-	}
208
-	return nil
209
-}
... ...
@@ -40,5 +40,5 @@ func getNamespaceFlags(namespaces libcontainer.Namespaces) (flag int) {
40 40
 	for _, ns := range namespaces {
41 41
 		flag |= namespaceMap[ns]
42 42
 	}
43
-	return
43
+	return flag
44 44
 }
... ...
@@ -1,6 +1,7 @@
1
-package nsinit
1
+package main
2 2
 
3 3
 import (
4
+	"encoding/json"
4 5
 	"fmt"
5 6
 	"github.com/dotcloud/docker/pkg/libcontainer"
6 7
 	"github.com/dotcloud/docker/pkg/libcontainer/capabilities"
... ...
@@ -12,103 +13,112 @@ import (
12 12
 	"syscall"
13 13
 )
14 14
 
15
-// InitNamespace should be run inside an existing namespace to setup
16
-// common mounts, drop capabilities, and setup network interfaces
17
-func InitNamespace(container *libcontainer.Container) error {
18
-	println("|||||||||||||")
19
-	if err := setLogFile(container); err != nil {
20
-		return err
15
+func loadContainer() (*libcontainer.Container, error) {
16
+	f, err := os.Open("container.json")
17
+	if err != nil {
18
+		return nil, err
21 19
 	}
22
-	println(container.LogFile)
23
-	log.Printf("--------->")
24
-	rootfs, err := resolveRootfs(container)
20
+	defer f.Close()
21
+
22
+	var container *libcontainer.Container
23
+	if err := json.NewDecoder(f).Decode(&container); err != nil {
24
+		return nil, err
25
+	}
26
+	return container, nil
27
+}
28
+
29
+func main() {
30
+	container, err := loadContainer()
25 31
 	if err != nil {
26
-		return err
32
+		log.Fatal(err)
27 33
 	}
28 34
 
29
-	// any errors encoutered inside the namespace we should write
30
-	// out to a log or a pipe to our parent and exit(1)
31
-	// because writing to stderr will not work after we close
32
-	if err := closeMasterAndStd(os.NewFile(container.Master, "/dev/ptmx")); err != nil {
33
-		log.Fatalf("close master and std %s", err)
34
-		return err
35
+	if os.Args[1] == "exec" {
36
+		_, err := namespaces.ExecContainer(container)
37
+		if err != nil {
38
+			log.Fatal(err)
39
+		}
40
+		os.Exit(0)
41
+	}
42
+	console := os.Args[1]
43
+
44
+	if err := setLogFile(container); err != nil {
45
+		log.Fatal(err)
35 46
 	}
36 47
 
37
-	slave, err := openTerminal(container.Console, syscall.O_RDWR)
48
+	rootfs, err := resolveRootfs()
49
+	if err != nil {
50
+		log.Fatal(err)
51
+	}
52
+
53
+	// close pipes so that we can replace it with the pty
54
+	os.Stdin.Close()
55
+	os.Stdout.Close()
56
+	os.Stderr.Close()
57
+
58
+	slave, err := openTerminal(console, syscall.O_RDWR)
38 59
 	if err != nil {
39 60
 		log.Fatalf("open terminal %s", err)
40
-		return err
61
+	}
62
+	if slave.Fd() != 0 {
63
+		log.Fatalf("slave fd should be 0")
41 64
 	}
42 65
 	if err := dupSlave(slave); err != nil {
43 66
 		log.Fatalf("dup2 slave %s", err)
44
-		return err
45 67
 	}
46 68
 
47
-	/*
48
-		if container.NetNsFd > 0 {
49
-			if err := joinExistingNamespace(container.NetNsFd, libcontainer.CLONE_NEWNET); err != nil {
50
-				log.Fatalf("join existing net namespace %s", err)
51
-			}
52
-		}
53
-	*/
54
-
55 69
 	if _, err := system.Setsid(); err != nil {
56 70
 		log.Fatalf("setsid %s", err)
57
-		return err
58 71
 	}
59 72
 	if err := system.Setctty(); err != nil {
60 73
 		log.Fatalf("setctty %s", err)
61
-		return err
62 74
 	}
63 75
 	if err := system.ParentDeathSignal(); err != nil {
64 76
 		log.Fatalf("parent deth signal %s", err)
65
-		return err
66 77
 	}
67
-	if err := namespaces.SetupNewMountNamespace(rootfs, container.Console, container.ReadonlyFs); err != nil {
78
+
79
+	if err := setupNewMountNamespace(rootfs, console, container.ReadonlyFs); err != nil {
68 80
 		log.Fatalf("setup mount namespace %s", err)
69
-		return err
70 81
 	}
82
+
83
+	if container.Network != nil {
84
+		if err := setupNetworking(container); err != nil {
85
+			log.Fatalf("setup networking %s", err)
86
+		}
87
+	}
88
+
71 89
 	if err := system.Sethostname(container.ID); err != nil {
72 90
 		log.Fatalf("sethostname %s", err)
73
-		return err
74 91
 	}
75 92
 	if err := capabilities.DropCapabilities(container); err != nil {
76 93
 		log.Fatalf("drop capabilities %s", err)
77
-		return err
78 94
 	}
79 95
 	if err := setupUser(container); err != nil {
80 96
 		log.Fatalf("setup user %s", err)
81
-		return err
82 97
 	}
83 98
 	if container.WorkingDir != "" {
84 99
 		if err := system.Chdir(container.WorkingDir); err != nil {
85 100
 			log.Fatalf("chdir to %s %s", container.WorkingDir, err)
86
-			return err
87 101
 		}
88 102
 	}
89 103
 	if err := system.Exec(container.Command.Args[0], container.Command.Args[0:], container.Command.Env); err != nil {
90 104
 		log.Fatalf("exec %s", err)
91
-		return err
92 105
 	}
93 106
 	panic("unreachable")
94 107
 }
95 108
 
96
-func resolveRootfs(container *libcontainer.Container) (string, error) {
97
-	rootfs, err := filepath.Abs(container.RootFs)
109
+func resolveRootfs() (string, error) {
110
+	cwd, err := os.Getwd()
111
+	if err != nil {
112
+		return "", err
113
+	}
114
+	rootfs, err := filepath.Abs(cwd)
98 115
 	if err != nil {
99 116
 		return "", err
100 117
 	}
101 118
 	return filepath.EvalSymlinks(rootfs)
102 119
 }
103 120
 
104
-func closeMasterAndStd(master *os.File) error {
105
-	master.Close()
106
-	os.Stdin.Close()
107
-	os.Stdout.Close()
108
-	os.Stderr.Close()
109
-	return nil
110
-}
111
-
112 121
 func setupUser(container *libcontainer.Container) error {
113 122
 	// TODO: honor user passed on container
114 123
 	if err := system.Setgroups(nil); err != nil {
... ...
@@ -154,3 +164,7 @@ func setLogFile(container *libcontainer.Container) error {
154 154
 	log.SetOutput(f)
155 155
 	return nil
156 156
 }
157
+
158
+func setupNetworking(conatiner *libcontainer.Container) error {
159
+	return nil
160
+}
157 161
new file mode 100644
... ...
@@ -0,0 +1,209 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"github.com/dotcloud/docker/pkg/system"
5
+	"log"
6
+	"os"
7
+	"path/filepath"
8
+	"syscall"
9
+)
10
+
11
+var (
12
+	// default mount point options
13
+	defaults = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV
14
+)
15
+
16
+func setupNewMountNamespace(rootfs, console string, readonly bool) error {
17
+	if err := system.Mount("", "/", "", syscall.MS_SLAVE|syscall.MS_REC, ""); err != nil {
18
+		return fmt.Errorf("mounting / as slave %s", err)
19
+	}
20
+
21
+	if err := system.Mount(rootfs, rootfs, "bind", syscall.MS_BIND|syscall.MS_REC, ""); err != nil {
22
+		return fmt.Errorf("mouting %s as bind %s", rootfs, err)
23
+	}
24
+
25
+	if readonly {
26
+		if err := system.Mount(rootfs, rootfs, "bind", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_REC, ""); err != nil {
27
+			return fmt.Errorf("mounting %s as readonly %s", rootfs, err)
28
+		}
29
+	}
30
+
31
+	if err := mountSystem(rootfs); err != nil {
32
+		return fmt.Errorf("mount system %s", err)
33
+	}
34
+
35
+	if err := copyDevNodes(rootfs); err != nil {
36
+		return fmt.Errorf("copy dev nodes %s", err)
37
+	}
38
+
39
+	ptmx := filepath.Join(rootfs, "dev/ptmx")
40
+	if err := os.Remove(ptmx); err != nil && !os.IsNotExist(err) {
41
+		return err
42
+	}
43
+	if err := os.Symlink("pts/ptmx", ptmx); err != nil {
44
+		return fmt.Errorf("symlink dev ptmx %s", err)
45
+	}
46
+
47
+	if err := setupDev(rootfs); err != nil {
48
+		return err
49
+	}
50
+
51
+	if err := setupConsole(rootfs, console); err != nil {
52
+		return err
53
+	}
54
+
55
+	if err := system.Chdir(rootfs); err != nil {
56
+		return fmt.Errorf("chdir into %s %s", rootfs, err)
57
+	}
58
+
59
+	if err := system.Mount(rootfs, "/", "", syscall.MS_MOVE, ""); err != nil {
60
+		return fmt.Errorf("mount move %s into / %s", rootfs, err)
61
+	}
62
+
63
+	if err := system.Chroot("."); err != nil {
64
+		return fmt.Errorf("chroot . %s", err)
65
+	}
66
+
67
+	if err := system.Chdir("/"); err != nil {
68
+		return fmt.Errorf("chdir / %s", err)
69
+	}
70
+
71
+	system.Umask(0022)
72
+
73
+	return nil
74
+}
75
+
76
+func copyDevNodes(rootfs string) error {
77
+	oldMask := system.Umask(0000)
78
+	defer system.Umask(oldMask)
79
+
80
+	for _, node := range []string{
81
+		"null",
82
+		"zero",
83
+		"full",
84
+		"random",
85
+		"urandom",
86
+		"tty",
87
+	} {
88
+		stat, err := os.Stat(filepath.Join("/dev", node))
89
+		if err != nil {
90
+			return err
91
+		}
92
+
93
+		var (
94
+			dest = filepath.Join(rootfs, "dev", node)
95
+			st   = stat.Sys().(*syscall.Stat_t)
96
+		)
97
+
98
+		log.Printf("copy %s to %s %d\n", node, dest, st.Rdev)
99
+		if err := system.Mknod(dest, st.Mode, int(st.Rdev)); err != nil && !os.IsExist(err) {
100
+			return fmt.Errorf("copy %s %s", node, err)
101
+		}
102
+	}
103
+	return nil
104
+}
105
+
106
+func setupDev(rootfs string) error {
107
+	for _, link := range []struct {
108
+		from string
109
+		to   string
110
+	}{
111
+		{"/proc/kcore", "/dev/core"},
112
+		{"/proc/self/fd", "/dev/fd"},
113
+		{"/proc/self/fd/0", "/dev/stdin"},
114
+		{"/proc/self/fd/1", "/dev/stdout"},
115
+		{"/proc/self/fd/2", "/dev/stderr"},
116
+	} {
117
+		dest := filepath.Join(rootfs, link.to)
118
+		if err := os.Remove(dest); err != nil && !os.IsNotExist(err) {
119
+			return fmt.Errorf("remove %s %s", dest, err)
120
+		}
121
+		if err := os.Symlink(link.from, dest); err != nil {
122
+			return fmt.Errorf("symlink %s %s", dest, err)
123
+		}
124
+	}
125
+	return nil
126
+}
127
+
128
+func setupConsole(rootfs, console string) error {
129
+	oldMask := system.Umask(0000)
130
+	defer system.Umask(oldMask)
131
+
132
+	stat, err := os.Stat(console)
133
+	if err != nil {
134
+		return fmt.Errorf("stat console %s %s", console, err)
135
+	}
136
+	st := stat.Sys().(*syscall.Stat_t)
137
+
138
+	dest := filepath.Join(rootfs, "dev/console")
139
+	if err := os.Remove(dest); err != nil && !os.IsNotExist(err) {
140
+		return fmt.Errorf("remove %s %s", dest, err)
141
+	}
142
+
143
+	if err := os.Chmod(console, 0600); err != nil {
144
+		return err
145
+	}
146
+	if err := os.Chown(console, 0, 0); err != nil {
147
+		return err
148
+	}
149
+
150
+	if err := system.Mknod(dest, (st.Mode&^07777)|0600, int(st.Rdev)); err != nil {
151
+		return fmt.Errorf("mknod %s %s", dest, err)
152
+	}
153
+
154
+	if err := system.Mount(console, dest, "bind", syscall.MS_BIND, ""); err != nil {
155
+		return fmt.Errorf("bind %s to %s %s", console, dest, err)
156
+	}
157
+	return nil
158
+}
159
+
160
+// mountSystem sets up linux specific system mounts like sys, proc, shm, and devpts
161
+// inside the mount namespace
162
+func mountSystem(rootfs string) error {
163
+	for _, m := range []struct {
164
+		source string
165
+		path   string
166
+		device string
167
+		flags  int
168
+		data   string
169
+	}{
170
+		{source: "proc", path: filepath.Join(rootfs, "proc"), device: "proc", flags: defaults},
171
+		{source: "sysfs", path: filepath.Join(rootfs, "sys"), device: "sysfs", flags: defaults},
172
+		{source: "tmpfs", path: filepath.Join(rootfs, "dev"), device: "tmpfs", flags: syscall.MS_NOSUID | syscall.MS_STRICTATIME, data: "mode=755"},
173
+		{source: "shm", path: filepath.Join(rootfs, "dev", "shm"), device: "tmpfs", flags: defaults, data: "mode=1777"},
174
+		{source: "devpts", path: filepath.Join(rootfs, "dev", "pts"), device: "devpts", flags: syscall.MS_NOSUID | syscall.MS_NOEXEC, data: "newinstance,ptmxmode=0666,mode=620,gid=5"},
175
+		{source: "tmpfs", path: filepath.Join(rootfs, "run"), device: "tmpfs", flags: syscall.MS_NOSUID | syscall.MS_NODEV | syscall.MS_STRICTATIME, data: "mode=755"},
176
+	} {
177
+		if err := os.MkdirAll(m.path, 0755); err != nil && !os.IsExist(err) {
178
+			return fmt.Errorf("mkdirall %s %s", m.path, err)
179
+		}
180
+		if err := system.Mount(m.source, m.path, m.device, uintptr(m.flags), m.data); err != nil {
181
+			return fmt.Errorf("mounting %s into %s %s", m.source, m.path, err)
182
+		}
183
+	}
184
+	return nil
185
+}
186
+
187
+func remountProc() error {
188
+	if err := system.Unmount("/proc", syscall.MNT_DETACH); err != nil {
189
+		return err
190
+	}
191
+	if err := system.Mount("proc", "/proc", "proc", uintptr(defaults), ""); err != nil {
192
+		return err
193
+	}
194
+	return nil
195
+}
196
+
197
+func remountSys() error {
198
+	if err := system.Unmount("/sys", syscall.MNT_DETACH); err != nil {
199
+		if err != syscall.EINVAL {
200
+			return err
201
+		}
202
+	} else {
203
+		if err := system.Mount("sysfs", "/sys", "sysfs", uintptr(defaults), ""); err != nil {
204
+			return err
205
+		}
206
+	}
207
+	return nil
208
+}
... ...
@@ -7,7 +7,6 @@ import (
7 7
 	"path/filepath"
8 8
 	"strconv"
9 9
 	"strings"
10
-	"syscall"
11 10
 )
12 11
 
13 12
 func addEnvIfNotSet(container *libcontainer.Container, key, value string) {
... ...
@@ -26,31 +25,6 @@ func addEnvIfNotSet(container *libcontainer.Container, key, value string) {
26 26
 	container.Command.Env = append(container.Command.Env, jv)
27 27
 }
28 28
 
29
-// getNsFds inspects the container's namespace configuration and opens the fds to
30
-// each of the namespaces.
31
-func getNsFds(container *libcontainer.Container) ([]uintptr, error) {
32
-	var (
33
-		namespaces = []string{}
34
-		fds        = []uintptr{}
35
-	)
36
-
37
-	for _, ns := range container.Namespaces {
38
-		namespaces = append(namespaces, namespaceFileMap[ns])
39
-	}
40
-
41
-	for _, ns := range namespaces {
42
-		fd, err := getNsFd(container.NsPid, ns)
43
-		if err != nil {
44
-			for _, fd = range fds {
45
-				syscall.Close(int(fd))
46
-			}
47
-			return nil, err
48
-		}
49
-		fds = append(fds, fd)
50
-	}
51
-	return fds, nil
52
-}
53
-
54 29
 // getNsFd returns the fd for a specific pid and namespace option
55 30
 func getNsFd(pid int, ns string) (uintptr, error) {
56 31
 	nspath := filepath.Join("/proc", strconv.Itoa(pid), "ns", ns)