Browse code

Simplify namespaces with only nsinit Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)

Michael Crosby authored on 2014/02/20 07:55:34
Showing 10 changed files
1 1
deleted file mode 100644
... ...
@@ -1,203 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"encoding/json"
5
-	"flag"
6
-	"fmt"
7
-	"github.com/dotcloud/docker/pkg/libcontainer"
8
-	"github.com/dotcloud/docker/pkg/libcontainer/namespaces"
9
-	"github.com/dotcloud/docker/pkg/libcontainer/namespaces/nsinit"
10
-	"github.com/dotcloud/docker/pkg/libcontainer/network"
11
-	"github.com/dotcloud/docker/pkg/libcontainer/utils"
12
-	"os"
13
-	exec_ "os/exec"
14
-	"path"
15
-	"path/filepath"
16
-)
17
-
18
-var (
19
-	displayPid bool
20
-	newCommand string
21
-	usrNet     bool
22
-	masterFd   int
23
-	console    string
24
-)
25
-
26
-func init() {
27
-	flag.BoolVar(&displayPid, "pid", false, "display the pid before waiting")
28
-	flag.StringVar(&newCommand, "cmd", "/bin/bash", "command to run in the existing namespace")
29
-	flag.BoolVar(&usrNet, "net", false, "user a net namespace")
30
-	flag.IntVar(&masterFd, "master", 0, "master fd")
31
-	flag.StringVar(&console, "console", "", "console path")
32
-	flag.Parse()
33
-}
34
-
35
-func nsinitFunc(container *libcontainer.Container) error {
36
-	container.Master = uintptr(masterFd)
37
-	container.Console = console
38
-	container.LogFile = "/root/logs"
39
-
40
-	return nsinit.InitNamespace(container)
41
-}
42
-
43
-func exec(container *libcontainer.Container) error {
44
-	var (
45
-		netFile *os.File
46
-		err     error
47
-	)
48
-	container.NetNsFd = 0
49
-
50
-	if usrNet {
51
-		netFile, err = os.Open("/root/nsroot/test")
52
-		if err != nil {
53
-			return err
54
-		}
55
-		container.NetNsFd = netFile.Fd()
56
-	}
57
-
58
-	self, err := exec_.LookPath(os.Args[0])
59
-	if err != nil {
60
-		return err
61
-	}
62
-	if output, err := exec_.Command("cp", self, path.Join(container.RootFs, ".nsinit")).CombinedOutput(); err != nil {
63
-		return fmt.Errorf("Error exec cp: %s, (%s)", err, output)
64
-	} else {
65
-		println(self, container.RootFs)
66
-		fmt.Printf("-----> %s\n", output)
67
-	}
68
-	println("----")
69
-
70
-	pid, err := namespaces.ExecContainer(container)
71
-	if err != nil {
72
-		return fmt.Errorf("error exec container %s", err)
73
-	}
74
-
75
-	if displayPid {
76
-		fmt.Println(pid)
77
-	}
78
-
79
-	exitcode, err := utils.WaitOnPid(pid)
80
-	if err != nil {
81
-		return fmt.Errorf("error waiting on child %s", err)
82
-	}
83
-	fmt.Println(exitcode)
84
-	if usrNet {
85
-		netFile.Close()
86
-		if err := network.DeleteNetworkNamespace("/root/nsroot/test"); err != nil {
87
-			return err
88
-		}
89
-	}
90
-	os.Exit(exitcode)
91
-	return nil
92
-}
93
-
94
-func execIn(container *libcontainer.Container) error {
95
-	// f, err := os.Open("/root/nsroot/test")
96
-	// if err != nil {
97
-	// 	return err
98
-	// }
99
-	// container.NetNsFd = f.Fd()
100
-	// pid, err := namespaces.ExecIn(container, &libcontainer.Command{
101
-	// 	Env: container.Command.Env,
102
-	// 	Args: []string{
103
-	// 		newCommand,
104
-	// 	},
105
-	// })
106
-	// if err != nil {
107
-	// 	return fmt.Errorf("error exexin container %s", err)
108
-	// }
109
-	// exitcode, err := utils.WaitOnPid(pid)
110
-	// if err != nil {
111
-	// 	return fmt.Errorf("error waiting on child %s", err)
112
-	// }
113
-	// os.Exit(exitcode)
114
-	return nil
115
-}
116
-
117
-func createNet(config *libcontainer.Network) error {
118
-	/*
119
-		root := "/root/nsroot"
120
-		if err := network.SetupNamespaceMountDir(root); err != nil {
121
-			return err
122
-		}
123
-
124
-		nspath := root + "/test"
125
-		if err := network.CreateNetworkNamespace(nspath); err != nil {
126
-			return nil
127
-		}
128
-		if err := network.CreateVethPair("veth0", config.TempVethName); err != nil {
129
-			return err
130
-		}
131
-		if err := network.SetInterfaceMaster("veth0", config.Bridge); err != nil {
132
-			return err
133
-		}
134
-		if err := network.InterfaceUp("veth0"); err != nil {
135
-			return err
136
-		}
137
-
138
-		f, err := os.Open(nspath)
139
-		if err != nil {
140
-			return err
141
-		}
142
-		defer f.Close()
143
-
144
-		if err := network.SetInterfaceInNamespaceFd("veth1", int(f.Fd())); err != nil {
145
-			return err
146
-		}
147
-
148
-			if err := network.SetupVethInsideNamespace(f.Fd(), config); err != nil {
149
-				return err
150
-			}
151
-	*/
152
-	return nil
153
-}
154
-
155
-func printErr(err error) {
156
-	fmt.Fprintln(os.Stderr, err)
157
-	os.Exit(1)
158
-}
159
-
160
-func main() {
161
-	cliCmd := flag.Arg(0)
162
-
163
-	config, err := filepath.Abs(flag.Arg(1))
164
-	if err != nil {
165
-		printErr(err)
166
-	}
167
-	println("cli:", cliCmd, "config:", config)
168
-	f, err := os.Open(config)
169
-	if err != nil {
170
-		printErr(err)
171
-	}
172
-
173
-	dec := json.NewDecoder(f)
174
-	var container *libcontainer.Container
175
-
176
-	if err := dec.Decode(&container); err != nil {
177
-		printErr(err)
178
-	}
179
-	f.Close()
180
-
181
-	switch cliCmd {
182
-	case "init":
183
-		err = nsinitFunc(container)
184
-	case "exec":
185
-		err = exec(container)
186
-	case "execin":
187
-		err = execIn(container)
188
-	case "net":
189
-		err = createNet(&libcontainer.Network{
190
-			TempVethName: "veth1",
191
-			IP:           "172.17.0.100/16",
192
-			Gateway:      "172.17.42.1",
193
-			Mtu:          1500,
194
-			Bridge:       "docker0",
195
-		})
196
-	default:
197
-		err = fmt.Errorf("command not supported: %s", cliCmd)
198
-	}
199
-
200
-	if err != nil {
201
-		printErr(err)
202
-	}
203
-}
204 1
deleted file mode 100644
... ...
@@ -1,76 +0,0 @@
1
-package namespaces
2
-
3
-import (
4
-	"github.com/dotcloud/docker/pkg/libcontainer"
5
-	"github.com/dotcloud/docker/pkg/system"
6
-	"github.com/dotcloud/docker/pkg/term"
7
-	"io"
8
-	"log"
9
-	"os"
10
-	"os/exec"
11
-	"syscall"
12
-)
13
-
14
-// ExecContainer will spawn new namespaces with the specified Container configuration
15
-// in the RootFs path and return the pid of the new containerized process.
16
-//
17
-// If an existing network namespace is specified the container
18
-// will join that namespace.  If an existing network namespace is not specified but CLONE_NEWNET is,
19
-// the container will be spawned with a new network namespace with no configuration.  Omiting an
20
-// existing network namespace and the CLONE_NEWNET option in the container configuration will allow
21
-// the container to the the host's networking options and configuration.
22
-func ExecContainer(container *libcontainer.Container) (pid int, err error) {
23
-	master, console, err := createMasterAndConsole()
24
-	if err != nil {
25
-		return -1, err
26
-	}
27
-
28
-	// we need CLONE_VFORK so we can wait on the child
29
-	flag := uintptr(getNamespaceFlags(container.Namespaces) | CLONE_VFORK)
30
-
31
-	command := exec.Command("nsinit", console)
32
-	command.SysProcAttr = &syscall.SysProcAttr{
33
-		Cloneflags: flag,
34
-	}
35
-
36
-	if err := command.Start(); err != nil {
37
-		return -1, err
38
-	}
39
-	pid = command.Process.Pid
40
-
41
-	go func() {
42
-		if _, err := io.Copy(os.Stdout, master); err != nil {
43
-			log.Println(err)
44
-		}
45
-	}()
46
-
47
-	go func() {
48
-		if _, err := io.Copy(master, os.Stdin); err != nil {
49
-			log.Println(err)
50
-		}
51
-	}()
52
-
53
-	term.SetRawTerminal(os.Stdin.Fd())
54
-
55
-	if err := command.Wait(); err != nil {
56
-		return pid, err
57
-	}
58
-	return pid, nil
59
-}
60
-
61
-func createMasterAndConsole() (*os.File, string, error) {
62
-	master, err := os.OpenFile("/dev/ptmx", syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_CLOEXEC, 0)
63
-	if err != nil {
64
-		return nil, "", err
65
-	}
66
-
67
-	console, err := system.Ptsname(master)
68
-	if err != nil {
69
-		return nil, "", err
70
-	}
71
-
72
-	if err := system.Unlockpt(master); err != nil {
73
-		return nil, "", err
74
-	}
75
-	return master, console, nil
76
-}
77 1
deleted file mode 100644
... ...
@@ -1,44 +0,0 @@
1
-package namespaces
2
-
3
-import (
4
-	"github.com/dotcloud/docker/pkg/libcontainer"
5
-)
6
-
7
-const (
8
-	SIGCHLD       = 0x14
9
-	CLONE_VFORK   = 0x00004000
10
-	CLONE_NEWNS   = 0x00020000
11
-	CLONE_NEWUTS  = 0x04000000
12
-	CLONE_NEWIPC  = 0x08000000
13
-	CLONE_NEWUSER = 0x10000000
14
-	CLONE_NEWPID  = 0x20000000
15
-	CLONE_NEWNET  = 0x40000000
16
-)
17
-
18
-var namespaceMap = map[libcontainer.Namespace]int{
19
-	"": 0,
20
-	libcontainer.CLONE_NEWNS:   CLONE_NEWNS,
21
-	libcontainer.CLONE_NEWUTS:  CLONE_NEWUTS,
22
-	libcontainer.CLONE_NEWIPC:  CLONE_NEWIPC,
23
-	libcontainer.CLONE_NEWUSER: CLONE_NEWUSER,
24
-	libcontainer.CLONE_NEWPID:  CLONE_NEWPID,
25
-	libcontainer.CLONE_NEWNET:  CLONE_NEWNET,
26
-}
27
-
28
-var namespaceFileMap = map[libcontainer.Namespace]string{
29
-	libcontainer.CLONE_NEWNS:   "mnt",
30
-	libcontainer.CLONE_NEWUTS:  "uts",
31
-	libcontainer.CLONE_NEWIPC:  "ipc",
32
-	libcontainer.CLONE_NEWUSER: "user",
33
-	libcontainer.CLONE_NEWPID:  "pid",
34
-	libcontainer.CLONE_NEWNET:  "net",
35
-}
36
-
37
-// getNamespaceFlags parses the container's Namespaces options to set the correct
38
-// flags on clone, unshare, and setns
39
-func getNamespaceFlags(namespaces libcontainer.Namespaces) (flag int) {
40
-	for _, ns := range namespaces {
41
-		flag |= namespaceMap[ns]
42
-	}
43
-	return flag
44
-}
45 1
deleted file mode 100644
... ...
@@ -1,170 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"encoding/json"
5
-	"fmt"
6
-	"github.com/dotcloud/docker/pkg/libcontainer"
7
-	"github.com/dotcloud/docker/pkg/libcontainer/capabilities"
8
-	"github.com/dotcloud/docker/pkg/libcontainer/namespaces"
9
-	"github.com/dotcloud/docker/pkg/system"
10
-	"log"
11
-	"os"
12
-	"path/filepath"
13
-	"syscall"
14
-)
15
-
16
-func loadContainer() (*libcontainer.Container, error) {
17
-	f, err := os.Open("container.json")
18
-	if err != nil {
19
-		return nil, err
20
-	}
21
-	defer f.Close()
22
-
23
-	var container *libcontainer.Container
24
-	if err := json.NewDecoder(f).Decode(&container); err != nil {
25
-		return nil, err
26
-	}
27
-	return container, nil
28
-}
29
-
30
-func main() {
31
-	container, err := loadContainer()
32
-	if err != nil {
33
-		log.Fatal(err)
34
-	}
35
-
36
-	if os.Args[1] == "exec" {
37
-		_, err := namespaces.ExecContainer(container)
38
-		if err != nil {
39
-			log.Fatal(err)
40
-		}
41
-		os.Exit(0)
42
-	}
43
-	console := os.Args[1]
44
-
45
-	if err := setLogFile(container); err != nil {
46
-		log.Fatal(err)
47
-	}
48
-
49
-	rootfs, err := resolveRootfs()
50
-	if err != nil {
51
-		log.Fatal(err)
52
-	}
53
-
54
-	// close pipes so that we can replace it with the pty
55
-	os.Stdin.Close()
56
-	os.Stdout.Close()
57
-	os.Stderr.Close()
58
-
59
-	slave, err := openTerminal(console, syscall.O_RDWR)
60
-	if err != nil {
61
-		log.Fatalf("open terminal %s", err)
62
-	}
63
-	if slave.Fd() != 0 {
64
-		log.Fatalf("slave fd should be 0")
65
-	}
66
-	if err := dupSlave(slave); err != nil {
67
-		log.Fatalf("dup2 slave %s", err)
68
-	}
69
-
70
-	if _, err := system.Setsid(); err != nil {
71
-		log.Fatalf("setsid %s", err)
72
-	}
73
-	if err := system.Setctty(); err != nil {
74
-		log.Fatalf("setctty %s", err)
75
-	}
76
-	if err := system.ParentDeathSignal(); err != nil {
77
-		log.Fatalf("parent deth signal %s", err)
78
-	}
79
-
80
-	if err := setupNewMountNamespace(rootfs, console, container.ReadonlyFs); err != nil {
81
-		log.Fatalf("setup mount namespace %s", err)
82
-	}
83
-
84
-	if container.Network != nil {
85
-		if err := setupNetworking(container); err != nil {
86
-			log.Fatalf("setup networking %s", err)
87
-		}
88
-	}
89
-
90
-	if err := system.Sethostname(container.ID); err != nil {
91
-		log.Fatalf("sethostname %s", err)
92
-	}
93
-	if err := capabilities.DropCapabilities(container); err != nil {
94
-		log.Fatalf("drop capabilities %s", err)
95
-	}
96
-	if err := setupUser(container); err != nil {
97
-		log.Fatalf("setup user %s", err)
98
-	}
99
-	if container.WorkingDir != "" {
100
-		if err := system.Chdir(container.WorkingDir); err != nil {
101
-			log.Fatalf("chdir to %s %s", container.WorkingDir, err)
102
-		}
103
-	}
104
-	if err := system.Exec(container.Command.Args[0], container.Command.Args[0:], container.Command.Env); err != nil {
105
-		log.Fatalf("exec %s", err)
106
-	}
107
-	panic("unreachable")
108
-}
109
-
110
-func resolveRootfs() (string, error) {
111
-	cwd, err := os.Getwd()
112
-	if err != nil {
113
-		return "", err
114
-	}
115
-	rootfs, err := filepath.Abs(cwd)
116
-	if err != nil {
117
-		return "", err
118
-	}
119
-	return filepath.EvalSymlinks(rootfs)
120
-}
121
-
122
-func setupUser(container *libcontainer.Container) error {
123
-	// TODO: honor user passed on container
124
-	if err := system.Setgroups(nil); err != nil {
125
-		return err
126
-	}
127
-	if err := system.Setresgid(0, 0, 0); err != nil {
128
-		return err
129
-	}
130
-	if err := system.Setresuid(0, 0, 0); err != nil {
131
-		return err
132
-	}
133
-	return nil
134
-}
135
-
136
-func dupSlave(slave *os.File) error {
137
-	// we close Stdin,etc so our pty slave should have fd 0
138
-	if slave.Fd() != 0 {
139
-		return fmt.Errorf("slave fd not 0 %d", slave.Fd())
140
-	}
141
-	if err := system.Dup2(slave.Fd(), 1); err != nil {
142
-		return err
143
-	}
144
-	if err := system.Dup2(slave.Fd(), 2); err != nil {
145
-		return err
146
-	}
147
-	return nil
148
-}
149
-
150
-// openTerminal is a clone of os.OpenFile without the O_CLOEXEC addition.
151
-func openTerminal(name string, flag int) (*os.File, error) {
152
-	r, e := syscall.Open(name, flag, 0)
153
-	if e != nil {
154
-		return nil, &os.PathError{"open", name, e}
155
-	}
156
-	return os.NewFile(uintptr(r), name), nil
157
-}
158
-
159
-func setLogFile(container *libcontainer.Container) error {
160
-	f, err := os.OpenFile(container.LogFile, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0655)
161
-	if err != nil {
162
-		return err
163
-	}
164
-	log.SetOutput(f)
165
-	return nil
166
-}
167
-
168
-func setupNetworking(conatiner *libcontainer.Container) error {
169
-	return nil
170
-}
171 1
deleted file mode 100644
... ...
@@ -1,209 +0,0 @@
1
-package main
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
-}
210 1
deleted file mode 100644
... ...
@@ -1,48 +0,0 @@
1
-package namespaces
2
-
3
-import (
4
-	"fmt"
5
-	"github.com/dotcloud/docker/pkg/libcontainer"
6
-	"os"
7
-	"path/filepath"
8
-	"strconv"
9
-	"strings"
10
-)
11
-
12
-func addEnvIfNotSet(container *libcontainer.Container, key, value string) {
13
-	jv := fmt.Sprintf("%s=%s", key, value)
14
-	if len(container.Command.Env) == 0 {
15
-		container.Command.Env = []string{jv}
16
-		return
17
-	}
18
-
19
-	for _, v := range container.Command.Env {
20
-		parts := strings.Split(v, "=")
21
-		if parts[0] == key {
22
-			return
23
-		}
24
-	}
25
-	container.Command.Env = append(container.Command.Env, jv)
26
-}
27
-
28
-// getNsFd returns the fd for a specific pid and namespace option
29
-func getNsFd(pid int, ns string) (uintptr, error) {
30
-	nspath := filepath.Join("/proc", strconv.Itoa(pid), "ns", ns)
31
-	// OpenFile adds closOnExec
32
-	f, err := os.OpenFile(nspath, os.O_RDONLY, 0666)
33
-	if err != nil {
34
-		return 0, err
35
-	}
36
-	return f.Fd(), nil
37
-}
38
-
39
-// setupEnvironment adds additional environment variables to the container's
40
-// Command such as USER, LOGNAME, container, and TERM
41
-func setupEnvironment(container *libcontainer.Container) {
42
-	addEnvIfNotSet(container, "container", "docker")
43
-	// TODO: check if pty
44
-	addEnvIfNotSet(container, "TERM", "xterm")
45
-	// TODO: get username from container
46
-	addEnvIfNotSet(container, "USER", "root")
47
-	addEnvIfNotSet(container, "LOGNAME", "root")
48
-}
49 1
new file mode 100644
... ...
@@ -0,0 +1,80 @@
0
+package main
1
+
2
+import (
3
+	"github.com/dotcloud/docker/pkg/libcontainer"
4
+	"github.com/dotcloud/docker/pkg/system"
5
+	"github.com/dotcloud/docker/pkg/term"
6
+	"io"
7
+	"log"
8
+	"os"
9
+	"os/exec"
10
+	"syscall"
11
+)
12
+
13
+func execCommand(container *libcontainer.Container) (pid int, err error) {
14
+	master, console, err := createMasterAndConsole()
15
+	if err != nil {
16
+		return -1, err
17
+	}
18
+
19
+	// we need CLONE_VFORK so we can wait on the child
20
+	flag := uintptr(getNamespaceFlags(container.Namespaces) | CLONE_VFORK)
21
+
22
+	command := exec.Command("nsinit", console)
23
+	command.SysProcAttr = &syscall.SysProcAttr{
24
+		Cloneflags: flag,
25
+	}
26
+
27
+	if err := command.Start(); err != nil {
28
+		return -1, err
29
+	}
30
+	pid = command.Process.Pid
31
+
32
+	go func() {
33
+		if _, err := io.Copy(os.Stdout, master); err != nil {
34
+			log.Println(err)
35
+		}
36
+	}()
37
+
38
+	go func() {
39
+		if _, err := io.Copy(master, os.Stdin); err != nil {
40
+			log.Println(err)
41
+		}
42
+	}()
43
+
44
+	ws, err := term.GetWinsize(os.Stdin.Fd())
45
+	if err != nil {
46
+		return -1, err
47
+	}
48
+	if err := term.SetWinsize(master.Fd(), ws); err != nil {
49
+		return -1, err
50
+	}
51
+	state, err := term.SetRawTerminal(os.Stdin.Fd())
52
+	if err != nil {
53
+		command.Process.Kill()
54
+		return -1, err
55
+	}
56
+	defer term.RestoreTerminal(os.Stdin.Fd(), state)
57
+
58
+	if err := command.Wait(); err != nil {
59
+		return pid, err
60
+	}
61
+	return pid, nil
62
+}
63
+
64
+func createMasterAndConsole() (*os.File, string, error) {
65
+	master, err := os.OpenFile("/dev/ptmx", syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_CLOEXEC, 0)
66
+	if err != nil {
67
+		return nil, "", err
68
+	}
69
+
70
+	console, err := system.Ptsname(master)
71
+	if err != nil {
72
+		return nil, "", err
73
+	}
74
+
75
+	if err := system.Unlockpt(master); err != nil {
76
+		return nil, "", err
77
+	}
78
+	return master, console, nil
79
+}
0 80
new file mode 100644
... ...
@@ -0,0 +1,171 @@
0
+package main
1
+
2
+import (
3
+	"encoding/json"
4
+	"fmt"
5
+	"github.com/dotcloud/docker/pkg/libcontainer"
6
+	"github.com/dotcloud/docker/pkg/libcontainer/capabilities"
7
+	"github.com/dotcloud/docker/pkg/system"
8
+	"log"
9
+	"os"
10
+	"path/filepath"
11
+	"syscall"
12
+)
13
+
14
+func loadContainer() (*libcontainer.Container, error) {
15
+	f, err := os.Open("container.json")
16
+	if err != nil {
17
+		return nil, err
18
+	}
19
+	defer f.Close()
20
+
21
+	var container *libcontainer.Container
22
+	if err := json.NewDecoder(f).Decode(&container); err != nil {
23
+		return nil, err
24
+	}
25
+	return container, nil
26
+}
27
+
28
+func main() {
29
+	container, err := loadContainer()
30
+	if err != nil {
31
+		log.Fatal(err)
32
+	}
33
+
34
+	if os.Args[1] == "exec" {
35
+		_, err := execCommand(container)
36
+		if err != nil {
37
+			log.Fatal(err)
38
+		}
39
+		os.Exit(0)
40
+	}
41
+	console := os.Args[1]
42
+
43
+	if err := setLogFile(container); err != nil {
44
+		log.Fatal(err)
45
+	}
46
+
47
+	rootfs, err := resolveRootfs()
48
+	if err != nil {
49
+		log.Fatal(err)
50
+	}
51
+
52
+	// close pipes so that we can replace it with the pty
53
+	os.Stdin.Close()
54
+	os.Stdout.Close()
55
+	os.Stderr.Close()
56
+
57
+	slave, err := openTerminal(console, syscall.O_RDWR)
58
+	if err != nil {
59
+		log.Fatalf("open terminal %s", err)
60
+	}
61
+	if slave.Fd() != 0 {
62
+		log.Fatalf("slave fd should be 0")
63
+	}
64
+	if err := dupSlave(slave); err != nil {
65
+		log.Fatalf("dup2 slave %s", err)
66
+	}
67
+
68
+	if _, err := system.Setsid(); err != nil {
69
+		log.Fatalf("setsid %s", err)
70
+	}
71
+	if err := system.Setctty(); err != nil {
72
+		log.Fatalf("setctty %s", err)
73
+	}
74
+	if err := system.ParentDeathSignal(); err != nil {
75
+		log.Fatalf("parent deth signal %s", err)
76
+	}
77
+
78
+	if err := setupNewMountNamespace(rootfs, console, container.ReadonlyFs); err != nil {
79
+		log.Fatalf("setup mount namespace %s", err)
80
+	}
81
+
82
+	if container.Network != nil {
83
+		if err := setupNetworking(container); err != nil {
84
+			log.Fatalf("setup networking %s", err)
85
+		}
86
+	}
87
+
88
+	if err := system.Sethostname(container.ID); err != nil {
89
+		log.Fatalf("sethostname %s", err)
90
+	}
91
+	if err := capabilities.DropCapabilities(container); err != nil {
92
+		log.Fatalf("drop capabilities %s", err)
93
+	}
94
+	if err := setupUser(container); err != nil {
95
+		log.Fatalf("setup user %s", err)
96
+	}
97
+	if container.WorkingDir != "" {
98
+		if err := system.Chdir(container.WorkingDir); err != nil {
99
+			log.Fatalf("chdir to %s %s", container.WorkingDir, err)
100
+		}
101
+	}
102
+	if err := system.Exec(container.Command.Args[0], container.Command.Args[0:], container.Command.Env); err != nil {
103
+		log.Fatalf("exec %s", err)
104
+	}
105
+	panic("unreachable")
106
+}
107
+
108
+func resolveRootfs() (string, error) {
109
+	cwd, err := os.Getwd()
110
+	if err != nil {
111
+		return "", err
112
+	}
113
+	rootfs, err := filepath.Abs(cwd)
114
+	if err != nil {
115
+		return "", err
116
+	}
117
+	return filepath.EvalSymlinks(rootfs)
118
+}
119
+
120
+func setupUser(container *libcontainer.Container) error {
121
+	// TODO: honor user passed on container
122
+	if err := system.Setgroups(nil); err != nil {
123
+		return err
124
+	}
125
+	if err := system.Setresgid(0, 0, 0); err != nil {
126
+		return err
127
+	}
128
+	if err := system.Setresuid(0, 0, 0); err != nil {
129
+		return err
130
+	}
131
+	return nil
132
+}
133
+
134
+func dupSlave(slave *os.File) error {
135
+	// we close Stdin,etc so our pty slave should have fd 0
136
+	if slave.Fd() != 0 {
137
+		return fmt.Errorf("slave fd not 0 %d", slave.Fd())
138
+	}
139
+	if err := system.Dup2(slave.Fd(), 1); err != nil {
140
+		return err
141
+	}
142
+	if err := system.Dup2(slave.Fd(), 2); err != nil {
143
+		return err
144
+	}
145
+	return nil
146
+}
147
+
148
+// openTerminal is a clone of os.OpenFile without the O_CLOEXEC addition.
149
+func openTerminal(name string, flag int) (*os.File, error) {
150
+	r, e := syscall.Open(name, flag, 0)
151
+	if e != nil {
152
+		return nil, &os.PathError{"open", name, e}
153
+	}
154
+	return os.NewFile(uintptr(r), name), nil
155
+}
156
+
157
+func setLogFile(container *libcontainer.Container) error {
158
+	if container.LogFile != "" {
159
+		f, err := os.OpenFile(container.LogFile, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0655)
160
+		if err != nil {
161
+			return err
162
+		}
163
+		log.SetOutput(f)
164
+	}
165
+	return nil
166
+}
167
+
168
+func setupNetworking(conatiner *libcontainer.Container) error {
169
+	return nil
170
+}
0 171
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
+}
0 209
new file mode 100644
... ...
@@ -0,0 +1,35 @@
0
+package main
1
+
2
+import (
3
+	"github.com/dotcloud/docker/pkg/libcontainer"
4
+)
5
+
6
+const (
7
+	SIGCHLD       = 0x14
8
+	CLONE_VFORK   = 0x00004000
9
+	CLONE_NEWNS   = 0x00020000
10
+	CLONE_NEWUTS  = 0x04000000
11
+	CLONE_NEWIPC  = 0x08000000
12
+	CLONE_NEWUSER = 0x10000000
13
+	CLONE_NEWPID  = 0x20000000
14
+	CLONE_NEWNET  = 0x40000000
15
+)
16
+
17
+var namespaceMap = map[libcontainer.Namespace]int{
18
+	"": 0,
19
+	libcontainer.CLONE_NEWNS:   CLONE_NEWNS,
20
+	libcontainer.CLONE_NEWUTS:  CLONE_NEWUTS,
21
+	libcontainer.CLONE_NEWIPC:  CLONE_NEWIPC,
22
+	libcontainer.CLONE_NEWUSER: CLONE_NEWUSER,
23
+	libcontainer.CLONE_NEWPID:  CLONE_NEWPID,
24
+	libcontainer.CLONE_NEWNET:  CLONE_NEWNET,
25
+}
26
+
27
+// getNamespaceFlags parses the container's Namespaces options to set the correct
28
+// flags on clone, unshare, and setns
29
+func getNamespaceFlags(namespaces libcontainer.Namespaces) (flag int) {
30
+	for _, ns := range namespaces {
31
+		flag |= namespaceMap[ns]
32
+	}
33
+	return flag
34
+}