From 9fc6058aa110d5b59c5068a289b6e3a30fc86f72 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Wed, 16 Jul 2014 15:15:29 -0700 Subject: [PATCH 1/4] Update libcontainer to be85764f109c3f0f62cd2a5c8be Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- hack/vendor.sh | 2 +- .../github.com/docker/libcontainer/Dockerfile | 8 ++ .../docker/libcontainer/cgroups/fs/cpuacct.go | 2 +- .../docker/libcontainer/console/console.go | 86 +++++++++++++++++-- .../docker/libcontainer/mount/init.go | 17 ++-- .../docker/libcontainer/mount/msmoveroot.go | 9 +- .../docker/libcontainer/mount/nodes/nodes.go | 7 +- .../docker/libcontainer/mount/pivotroot.go | 12 +-- .../docker/libcontainer/mount/ptmx.go | 6 +- .../docker/libcontainer/mount/readonly.go | 3 +- .../docker/libcontainer/mount/remount.go | 16 ++-- .../docker/libcontainer/namespaces/exec.go | 38 ++++---- .../docker/libcontainer/namespaces/execin.go | 2 +- .../docker/libcontainer/namespaces/init.go | 18 ++-- .../libcontainer/namespaces/std_term.go | 49 ----------- .../docker/libcontainer/namespaces/term.go | 29 ------- .../libcontainer/namespaces/tty_term.go | 56 ------------ .../libcontainer/namespaces/unsupported.go | 28 ------ .../docker/libcontainer/network/loopback.go | 4 +- .../docker/libcontainer/network/netns.go | 5 +- .../docker/libcontainer/network/types.go | 1 + .../docker/libcontainer/nsinit/exec.go | 66 ++++++++++++-- .../security/restrict/restrict.go | 10 +-- .../docker/libcontainer/selinux/selinux.go | 13 +-- .../docker/libcontainer/system/linux.go | 60 +++++++++++++ .../docker/libcontainer/system/proc.go | 27 ++++++ .../docker/libcontainer/system/setns_linux.go | 29 +++++++ .../docker/libcontainer/system/sysconfig.go | 13 +++ .../libcontainer/system/xattrs_linux.go | 59 +++++++++++++ 29 files changed, 422 insertions(+), 253 deletions(-) create mode 100644 vendor/src/github.com/docker/libcontainer/Dockerfile delete mode 100644 vendor/src/github.com/docker/libcontainer/namespaces/std_term.go delete mode 100644 vendor/src/github.com/docker/libcontainer/namespaces/term.go delete mode 100644 vendor/src/github.com/docker/libcontainer/namespaces/tty_term.go delete mode 100644 vendor/src/github.com/docker/libcontainer/namespaces/unsupported.go create mode 100644 vendor/src/github.com/docker/libcontainer/system/linux.go create mode 100644 vendor/src/github.com/docker/libcontainer/system/proc.go create mode 100644 vendor/src/github.com/docker/libcontainer/system/setns_linux.go create mode 100644 vendor/src/github.com/docker/libcontainer/system/sysconfig.go create mode 100644 vendor/src/github.com/docker/libcontainer/system/xattrs_linux.go diff --git a/hack/vendor.sh b/hack/vendor.sh index 93ecc8131..f3347d374 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -63,4 +63,4 @@ mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar clone git github.com/godbus/dbus v1 clone git github.com/coreos/go-systemd v2 -clone git github.com/docker/libcontainer fb67bb80b4205bece36ff7096ee745ab0cee7e06 +clone git github.com/docker/libcontainer be85764f109c3f0f62cd2a5c8be9af7a599798cf diff --git a/vendor/src/github.com/docker/libcontainer/Dockerfile b/vendor/src/github.com/docker/libcontainer/Dockerfile new file mode 100644 index 000000000..73789d1ab --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/Dockerfile @@ -0,0 +1,8 @@ +FROM crosbymichael/golang + +RUN apt-get update && apt-get install -y gcc + +ADD . /go/src/github.com/docker/libcontainer +RUN cd /go/src/github.com/docker/libcontainer && go get -d ./... && go install ./... + +CMD ["nsinit"] diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuacct.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuacct.go index be1805205..7979009c0 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuacct.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuacct.go @@ -12,7 +12,7 @@ import ( "time" "github.com/docker/libcontainer/cgroups" - "github.com/dotcloud/docker/pkg/system" + "github.com/docker/libcontainer/system" ) var ( diff --git a/vendor/src/github.com/docker/libcontainer/console/console.go b/vendor/src/github.com/docker/libcontainer/console/console.go index 519b5644c..c0d1fb043 100644 --- a/vendor/src/github.com/docker/libcontainer/console/console.go +++ b/vendor/src/github.com/docker/libcontainer/console/console.go @@ -7,22 +7,24 @@ import ( "os" "path/filepath" "syscall" + "unsafe" "github.com/docker/libcontainer/label" - "github.com/dotcloud/docker/pkg/system" ) // Setup initializes the proper /dev/console inside the rootfs path func Setup(rootfs, consolePath, mountLabel string) error { - oldMask := system.Umask(0000) - defer system.Umask(oldMask) + oldMask := syscall.Umask(0000) + defer syscall.Umask(oldMask) if err := os.Chmod(consolePath, 0600); err != nil { return err } + if err := os.Chown(consolePath, 0, 0); err != nil { return err } + if err := label.SetFileLabel(consolePath, mountLabel); err != nil { return fmt.Errorf("set file label %s %s", consolePath, err) } @@ -33,26 +35,94 @@ func Setup(rootfs, consolePath, mountLabel string) error { if err != nil && !os.IsExist(err) { return fmt.Errorf("create %s %s", dest, err) } + if f != nil { f.Close() } - if err := system.Mount(consolePath, dest, "bind", syscall.MS_BIND, ""); err != nil { + if err := syscall.Mount(consolePath, dest, "bind", syscall.MS_BIND, ""); err != nil { return fmt.Errorf("bind %s to %s %s", consolePath, dest, err) } + return nil } func OpenAndDup(consolePath string) error { - slave, err := system.OpenTerminal(consolePath, syscall.O_RDWR) + slave, err := OpenTerminal(consolePath, syscall.O_RDWR) if err != nil { return fmt.Errorf("open terminal %s", err) } - if err := system.Dup2(slave.Fd(), 0); err != nil { + + if err := syscall.Dup2(int(slave.Fd()), 0); err != nil { return err } - if err := system.Dup2(slave.Fd(), 1); err != nil { + + if err := syscall.Dup2(int(slave.Fd()), 1); err != nil { return err } - return system.Dup2(slave.Fd(), 2) + + return syscall.Dup2(int(slave.Fd()), 2) +} + +// Unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. +// Unlockpt should be called before opening the slave side of a pseudoterminal. +func Unlockpt(f *os.File) error { + var u int + + return Ioctl(f.Fd(), syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))) +} + +// Ptsname retrieves the name of the first available pts for the given master. +func Ptsname(f *os.File) (string, error) { + var n int + + if err := Ioctl(f.Fd(), syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n))); err != nil { + return "", err + } + + return fmt.Sprintf("/dev/pts/%d", n), nil +} + +// CreateMasterAndConsole will open /dev/ptmx on the host and retreive the +// pts name for use as the pty slave inside the container +func CreateMasterAndConsole() (*os.File, string, error) { + master, err := os.OpenFile("/dev/ptmx", syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_CLOEXEC, 0) + if err != nil { + return nil, "", err + } + + console, err := Ptsname(master) + if err != nil { + return nil, "", err + } + + if err := Unlockpt(master); err != nil { + return nil, "", err + } + + return master, console, nil +} + +// OpenPtmx opens /dev/ptmx, i.e. the PTY master. +func OpenPtmx() (*os.File, error) { + // O_NOCTTY and O_CLOEXEC are not present in os package so we use the syscall's one for all. + return os.OpenFile("/dev/ptmx", syscall.O_RDONLY|syscall.O_NOCTTY|syscall.O_CLOEXEC, 0) +} + +// OpenTerminal is a clone of os.OpenFile without the O_CLOEXEC +// used to open the pty slave inside the container namespace +func OpenTerminal(name string, flag int) (*os.File, error) { + r, e := syscall.Open(name, flag, 0) + if e != nil { + return nil, &os.PathError{"open", name, e} + } + return os.NewFile(uintptr(r), name), nil +} + +func Ioctl(fd uintptr, flag, data uintptr) error { + if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, flag, data); err != 0 { + return err + } + + return nil } diff --git a/vendor/src/github.com/docker/libcontainer/mount/init.go b/vendor/src/github.com/docker/libcontainer/mount/init.go index 10f073890..daec6ac86 100644 --- a/vendor/src/github.com/docker/libcontainer/mount/init.go +++ b/vendor/src/github.com/docker/libcontainer/mount/init.go @@ -11,7 +11,6 @@ import ( "github.com/docker/libcontainer/label" "github.com/docker/libcontainer/mount/nodes" "github.com/dotcloud/docker/pkg/symlink" - "github.com/dotcloud/docker/pkg/system" ) // default mount point flags @@ -35,10 +34,10 @@ func InitializeMountNamespace(rootfs, console string, mountConfig *MountConfig) if mountConfig.NoPivotRoot { flag = syscall.MS_SLAVE } - if err := system.Mount("", "/", "", uintptr(flag|syscall.MS_REC), ""); err != nil { + if err := syscall.Mount("", "/", "", uintptr(flag|syscall.MS_REC), ""); err != nil { return fmt.Errorf("mounting / with flags %X %s", (flag | syscall.MS_REC), err) } - if err := system.Mount(rootfs, rootfs, "bind", syscall.MS_BIND|syscall.MS_REC, ""); err != nil { + if err := syscall.Mount(rootfs, rootfs, "bind", syscall.MS_BIND|syscall.MS_REC, ""); err != nil { return fmt.Errorf("mouting %s as bind %s", rootfs, err) } if err := mountSystem(rootfs, mountConfig); err != nil { @@ -56,7 +55,7 @@ func InitializeMountNamespace(rootfs, console string, mountConfig *MountConfig) if err := setupDevSymlinks(rootfs); err != nil { return fmt.Errorf("dev symlinks %s", err) } - if err := system.Chdir(rootfs); err != nil { + if err := syscall.Chdir(rootfs); err != nil { return fmt.Errorf("chdir into %s %s", rootfs, err) } @@ -75,7 +74,7 @@ func InitializeMountNamespace(rootfs, console string, mountConfig *MountConfig) } } - system.Umask(0022) + syscall.Umask(0022) return nil } @@ -87,7 +86,7 @@ func mountSystem(rootfs string, mountConfig *MountConfig) error { if err := os.MkdirAll(m.path, 0755); err != nil && !os.IsExist(err) { return fmt.Errorf("mkdirall %s %s", m.path, err) } - if err := system.Mount(m.source, m.path, m.device, uintptr(m.flags), m.data); err != nil { + if err := syscall.Mount(m.source, m.path, m.device, uintptr(m.flags), m.data); err != nil { return fmt.Errorf("mounting %s into %s %s", m.source, m.path, err) } } @@ -169,11 +168,11 @@ func setupBindmounts(rootfs string, mountConfig *MountConfig) error { return fmt.Errorf("Creating new bind-mount target, %s", err) } - if err := system.Mount(m.Source, dest, "bind", uintptr(flags), ""); err != nil { + if err := syscall.Mount(m.Source, dest, "bind", uintptr(flags), ""); err != nil { return fmt.Errorf("mounting %s into %s %s", m.Source, dest, err) } if !m.Writable { - if err := system.Mount(m.Source, dest, "bind", uintptr(flags|syscall.MS_REMOUNT), ""); err != nil { + if err := syscall.Mount(m.Source, dest, "bind", uintptr(flags|syscall.MS_REMOUNT), ""); err != nil { return fmt.Errorf("remounting %s into %s %s", m.Source, dest, err) } } @@ -183,7 +182,7 @@ func setupBindmounts(rootfs string, mountConfig *MountConfig) error { } } if m.Private { - if err := system.Mount("", dest, "none", uintptr(syscall.MS_PRIVATE), ""); err != nil { + if err := syscall.Mount("", dest, "none", uintptr(syscall.MS_PRIVATE), ""); err != nil { return fmt.Errorf("mounting %s private %s", dest, err) } } diff --git a/vendor/src/github.com/docker/libcontainer/mount/msmoveroot.go b/vendor/src/github.com/docker/libcontainer/mount/msmoveroot.go index b336c8649..94afd3a99 100644 --- a/vendor/src/github.com/docker/libcontainer/mount/msmoveroot.go +++ b/vendor/src/github.com/docker/libcontainer/mount/msmoveroot.go @@ -4,16 +4,17 @@ package mount import ( "fmt" - "github.com/dotcloud/docker/pkg/system" "syscall" ) func MsMoveRoot(rootfs string) error { - if err := system.Mount(rootfs, "/", "", syscall.MS_MOVE, ""); err != nil { + if err := syscall.Mount(rootfs, "/", "", syscall.MS_MOVE, ""); err != nil { return fmt.Errorf("mount move %s into / %s", rootfs, err) } - if err := system.Chroot("."); err != nil { + + if err := syscall.Chroot("."); err != nil { return fmt.Errorf("chroot . %s", err) } - return system.Chdir("/") + + return syscall.Chdir("/") } diff --git a/vendor/src/github.com/docker/libcontainer/mount/nodes/nodes.go b/vendor/src/github.com/docker/libcontainer/mount/nodes/nodes.go index e3420b48b..6a984e33f 100644 --- a/vendor/src/github.com/docker/libcontainer/mount/nodes/nodes.go +++ b/vendor/src/github.com/docker/libcontainer/mount/nodes/nodes.go @@ -9,13 +9,12 @@ import ( "syscall" "github.com/docker/libcontainer/devices" - "github.com/dotcloud/docker/pkg/system" ) // Create the device nodes in the container. func CreateDeviceNodes(rootfs string, nodesToCreate []*devices.Device) error { - oldMask := system.Umask(0000) - defer system.Umask(oldMask) + oldMask := syscall.Umask(0000) + defer syscall.Umask(oldMask) for _, node := range nodesToCreate { if err := CreateDeviceNode(rootfs, node); err != nil { @@ -46,7 +45,7 @@ func CreateDeviceNode(rootfs string, node *devices.Device) error { return fmt.Errorf("%c is not a valid device type for device %s", node.Type, node.Path) } - if err := system.Mknod(dest, uint32(fileMode), devices.Mkdev(node.MajorNumber, node.MinorNumber)); err != nil && !os.IsExist(err) { + if err := syscall.Mknod(dest, uint32(fileMode), devices.Mkdev(node.MajorNumber, node.MinorNumber)); err != nil && !os.IsExist(err) { return fmt.Errorf("mknod %s %s", node.Path, err) } return nil diff --git a/vendor/src/github.com/docker/libcontainer/mount/pivotroot.go b/vendor/src/github.com/docker/libcontainer/mount/pivotroot.go index ffd605136..a88ed4a84 100644 --- a/vendor/src/github.com/docker/libcontainer/mount/pivotroot.go +++ b/vendor/src/github.com/docker/libcontainer/mount/pivotroot.go @@ -8,8 +8,6 @@ import ( "os" "path/filepath" "syscall" - - "github.com/dotcloud/docker/pkg/system" ) func PivotRoot(rootfs string) error { @@ -17,16 +15,20 @@ func PivotRoot(rootfs string) error { if err != nil { return fmt.Errorf("can't create pivot_root dir %s, error %v", pivotDir, err) } - if err := system.Pivotroot(rootfs, pivotDir); err != nil { + + if err := syscall.PivotRoot(rootfs, pivotDir); err != nil { return fmt.Errorf("pivot_root %s", err) } - if err := system.Chdir("/"); err != nil { + + if err := syscall.Chdir("/"); err != nil { return fmt.Errorf("chdir / %s", err) } + // path to pivot dir now changed, update pivotDir = filepath.Join("/", filepath.Base(pivotDir)) - if err := system.Unmount(pivotDir, syscall.MNT_DETACH); err != nil { + if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil { return fmt.Errorf("unmount pivot_root dir %s", err) } + return os.Remove(pivotDir) } diff --git a/vendor/src/github.com/docker/libcontainer/mount/ptmx.go b/vendor/src/github.com/docker/libcontainer/mount/ptmx.go index 32c025202..c316481ad 100644 --- a/vendor/src/github.com/docker/libcontainer/mount/ptmx.go +++ b/vendor/src/github.com/docker/libcontainer/mount/ptmx.go @@ -4,9 +4,10 @@ package mount import ( "fmt" - "github.com/docker/libcontainer/console" "os" "path/filepath" + + "github.com/docker/libcontainer/console" ) func SetupPtmx(rootfs, consolePath, mountLabel string) error { @@ -14,13 +15,16 @@ func SetupPtmx(rootfs, consolePath, mountLabel string) error { if err := os.Remove(ptmx); err != nil && !os.IsNotExist(err) { return err } + if err := os.Symlink("pts/ptmx", ptmx); err != nil { return fmt.Errorf("symlink dev ptmx %s", err) } + if consolePath != "" { if err := console.Setup(rootfs, consolePath, mountLabel); err != nil { return err } } + return nil } diff --git a/vendor/src/github.com/docker/libcontainer/mount/readonly.go b/vendor/src/github.com/docker/libcontainer/mount/readonly.go index 0658358ad..9b4a6f704 100644 --- a/vendor/src/github.com/docker/libcontainer/mount/readonly.go +++ b/vendor/src/github.com/docker/libcontainer/mount/readonly.go @@ -3,10 +3,9 @@ package mount import ( - "github.com/dotcloud/docker/pkg/system" "syscall" ) func SetReadonly() error { - return system.Mount("/", "/", "bind", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_REC, "") + return syscall.Mount("/", "/", "bind", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_REC, "") } diff --git a/vendor/src/github.com/docker/libcontainer/mount/remount.go b/vendor/src/github.com/docker/libcontainer/mount/remount.go index 3e00509ae..99a01209d 100644 --- a/vendor/src/github.com/docker/libcontainer/mount/remount.go +++ b/vendor/src/github.com/docker/libcontainer/mount/remount.go @@ -2,30 +2,30 @@ package mount -import ( - "github.com/dotcloud/docker/pkg/system" - "syscall" -) +import "syscall" func RemountProc() error { - if err := system.Unmount("/proc", syscall.MNT_DETACH); err != nil { + if err := syscall.Unmount("/proc", syscall.MNT_DETACH); err != nil { return err } - if err := system.Mount("proc", "/proc", "proc", uintptr(defaultMountFlags), ""); err != nil { + + if err := syscall.Mount("proc", "/proc", "proc", uintptr(defaultMountFlags), ""); err != nil { return err } + return nil } func RemountSys() error { - if err := system.Unmount("/sys", syscall.MNT_DETACH); err != nil { + if err := syscall.Unmount("/sys", syscall.MNT_DETACH); err != nil { if err != syscall.EINVAL { return err } } else { - if err := system.Mount("sysfs", "/sys", "sysfs", uintptr(defaultMountFlags), ""); err != nil { + if err := syscall.Mount("sysfs", "/sys", "sysfs", uintptr(defaultMountFlags), ""); err != nil { return err } } + return nil } diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/exec.go b/vendor/src/github.com/docker/libcontainer/namespaces/exec.go index 9053f632a..6f3838fd2 100644 --- a/vendor/src/github.com/docker/libcontainer/namespaces/exec.go +++ b/vendor/src/github.com/docker/libcontainer/namespaces/exec.go @@ -3,6 +3,7 @@ package namespaces import ( + "io" "os" "os/exec" "syscall" @@ -13,18 +14,16 @@ import ( "github.com/docker/libcontainer/cgroups/systemd" "github.com/docker/libcontainer/network" "github.com/docker/libcontainer/syncpipe" - "github.com/dotcloud/docker/pkg/system" + "github.com/docker/libcontainer/system" ) // TODO(vishh): This is part of the libcontainer API and it does much more than just namespaces related work. // Move this to libcontainer package. // Exec performs setup outside of a namespace so that a container can be // executed. Exec is a high level function for working with container namespaces. -func Exec(container *libcontainer.Config, term Terminal, rootfs, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) { +func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Writer, console string, rootfs, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) { var ( - master *os.File - console string - err error + err error ) // create a pipe so that we can syncronize with the namespaced process and @@ -35,20 +34,13 @@ func Exec(container *libcontainer.Config, term Terminal, rootfs, dataPath string } defer syncPipe.Close() - if container.Tty { - master, console, err = system.CreateMasterAndConsole() - if err != nil { - return -1, err - } - term.SetMaster(master) - } - command := createCommand(container, console, rootfs, dataPath, os.Args[0], syncPipe.Child(), args) - - if err := term.Attach(command); err != nil { - return -1, err - } - defer term.Close() + // Note: these are only used in non-tty mode + // if there is a tty for the container it will be opened within the namespace and the + // fds will be duped to stdin, stdiout, and stderr + command.Stdin = stdin + command.Stdout = stdout + command.Stderr = stderr if err := command.Start(); err != nil { return -1, err @@ -110,6 +102,7 @@ func Exec(container *libcontainer.Config, term Terminal, rootfs, dataPath string return -1, err } } + return command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil } @@ -145,7 +138,11 @@ func DefaultCreateCommand(container *libcontainer.Config, console, rootfs, dataP command.Dir = rootfs command.Env = append(os.Environ(), env...) - system.SetCloneFlags(command, uintptr(GetNamespaceFlags(container.Namespaces))) + if command.SysProcAttr == nil { + command.SysProcAttr = &syscall.SysProcAttr{} + } + command.SysProcAttr.Cloneflags = uintptr(GetNamespaceFlags(container.Namespaces)) + command.SysProcAttr.Pdeathsig = syscall.SIGKILL command.ExtraFiles = []*os.File{pipe} @@ -157,11 +154,14 @@ func DefaultCreateCommand(container *libcontainer.Config, console, rootfs, dataP func SetupCgroups(container *libcontainer.Config, nspid int) (cgroups.ActiveCgroup, error) { if container.Cgroups != nil { c := container.Cgroups + if systemd.UseSystemd() { return systemd.Apply(c, nspid) } + return fs.Apply(c, nspid) } + return nil, nil } diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/execin.go b/vendor/src/github.com/docker/libcontainer/namespaces/execin.go index 3e79f4cda..5311adf2b 100644 --- a/vendor/src/github.com/docker/libcontainer/namespaces/execin.go +++ b/vendor/src/github.com/docker/libcontainer/namespaces/execin.go @@ -9,7 +9,7 @@ import ( "github.com/docker/libcontainer" "github.com/docker/libcontainer/label" - "github.com/dotcloud/docker/pkg/system" + "github.com/docker/libcontainer/system" ) // ExecIn uses an existing pid and joins the pid's namespaces with the new command. diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/init.go b/vendor/src/github.com/docker/libcontainer/namespaces/init.go index 4674944cb..7c917c015 100644 --- a/vendor/src/github.com/docker/libcontainer/namespaces/init.go +++ b/vendor/src/github.com/docker/libcontainer/namespaces/init.go @@ -19,8 +19,8 @@ import ( "github.com/docker/libcontainer/security/capabilities" "github.com/docker/libcontainer/security/restrict" "github.com/docker/libcontainer/syncpipe" + "github.com/docker/libcontainer/system" "github.com/docker/libcontainer/utils" - "github.com/dotcloud/docker/pkg/system" "github.com/dotcloud/docker/pkg/user" ) @@ -57,7 +57,7 @@ func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syn return err } } - if _, err := system.Setsid(); err != nil { + if _, err := syscall.Setsid(); err != nil { return fmt.Errorf("setsid %s", err) } if consolePath != "" { @@ -81,7 +81,7 @@ func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syn } if container.Hostname != "" { - if err := system.Sethostname(container.Hostname); err != nil { + if err := syscall.Sethostname([]byte(container.Hostname)); err != nil { return fmt.Errorf("sethostname %s", err) } } @@ -155,15 +155,19 @@ func SetupUser(u string) error { if err != nil { return fmt.Errorf("get supplementary groups %s", err) } - if err := system.Setgroups(suppGids); err != nil { + + if err := syscall.Setgroups(suppGids); err != nil { return fmt.Errorf("setgroups %s", err) } - if err := system.Setgid(gid); err != nil { + + if err := syscall.Setgid(gid); err != nil { return fmt.Errorf("setgid %s", err) } - if err := system.Setuid(uid); err != nil { + + if err := syscall.Setuid(uid); err != nil { return fmt.Errorf("setuid %s", err) } + return nil } @@ -229,7 +233,7 @@ func FinalizeNamespace(container *libcontainer.Config) error { } if container.WorkingDir != "" { - if err := system.Chdir(container.WorkingDir); err != nil { + if err := syscall.Chdir(container.WorkingDir); err != nil { return fmt.Errorf("chdir to %s %s", container.WorkingDir, err) } } diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/std_term.go b/vendor/src/github.com/docker/libcontainer/namespaces/std_term.go deleted file mode 100644 index 324336af2..000000000 --- a/vendor/src/github.com/docker/libcontainer/namespaces/std_term.go +++ /dev/null @@ -1,49 +0,0 @@ -package namespaces - -import ( - "io" - "os" - "os/exec" -) - -type StdTerminal struct { - stdin io.Reader - stdout, stderr io.Writer -} - -func (s *StdTerminal) SetMaster(*os.File) { - // no need to set master on non tty -} - -func (s *StdTerminal) Close() error { - return nil -} - -func (s *StdTerminal) Resize(h, w int) error { - return nil -} - -func (s *StdTerminal) Attach(command *exec.Cmd) error { - inPipe, err := command.StdinPipe() - if err != nil { - return err - } - outPipe, err := command.StdoutPipe() - if err != nil { - return err - } - errPipe, err := command.StderrPipe() - if err != nil { - return err - } - - go func() { - defer inPipe.Close() - io.Copy(inPipe, s.stdin) - }() - - go io.Copy(s.stdout, outPipe) - go io.Copy(s.stderr, errPipe) - - return nil -} diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/term.go b/vendor/src/github.com/docker/libcontainer/namespaces/term.go deleted file mode 100644 index 2a50bf855..000000000 --- a/vendor/src/github.com/docker/libcontainer/namespaces/term.go +++ /dev/null @@ -1,29 +0,0 @@ -package namespaces - -import ( - "io" - "os" - "os/exec" -) - -type Terminal interface { - io.Closer - SetMaster(*os.File) - Attach(*exec.Cmd) error - Resize(h, w int) error -} - -func NewTerminal(stdin io.Reader, stdout, stderr io.Writer, tty bool) Terminal { - if tty { - return &TtyTerminal{ - stdin: stdin, - stdout: stdout, - stderr: stderr, - } - } - return &StdTerminal{ - stdin: stdin, - stdout: stdout, - stderr: stderr, - } -} diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/tty_term.go b/vendor/src/github.com/docker/libcontainer/namespaces/tty_term.go deleted file mode 100644 index 272cf2cd6..000000000 --- a/vendor/src/github.com/docker/libcontainer/namespaces/tty_term.go +++ /dev/null @@ -1,56 +0,0 @@ -package namespaces - -import ( - "io" - "os" - "os/exec" - - "github.com/dotcloud/docker/pkg/term" -) - -type TtyTerminal struct { - stdin io.Reader - stdout, stderr io.Writer - master *os.File - state *term.State -} - -func (t *TtyTerminal) Resize(h, w int) error { - return term.SetWinsize(t.master.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)}) -} - -func (t *TtyTerminal) SetMaster(master *os.File) { - t.master = master -} - -func (t *TtyTerminal) Attach(command *exec.Cmd) error { - go io.Copy(t.stdout, t.master) - go io.Copy(t.master, t.stdin) - - state, err := t.setupWindow(t.master, os.Stdin) - - if err != nil { - return err - } - - t.state = state - return err -} - -// SetupWindow gets the parent window size and sets the master -// pty to the current size and set the parents mode to RAW -func (t *TtyTerminal) setupWindow(master, parent *os.File) (*term.State, error) { - ws, err := term.GetWinsize(parent.Fd()) - if err != nil { - return nil, err - } - if err := term.SetWinsize(master.Fd(), ws); err != nil { - return nil, err - } - return term.SetRawTerminal(parent.Fd()) -} - -func (t *TtyTerminal) Close() error { - term.RestoreTerminal(os.Stdin.Fd(), t.state) - return t.master.Close() -} diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/unsupported.go b/vendor/src/github.com/docker/libcontainer/namespaces/unsupported.go deleted file mode 100644 index 8398b94d7..000000000 --- a/vendor/src/github.com/docker/libcontainer/namespaces/unsupported.go +++ /dev/null @@ -1,28 +0,0 @@ -// +build !linux - -package namespaces - -import ( - "github.com/docker/libcontainer" - "github.com/docker/libcontainer/cgroups" -) - -func Exec(container *libcontainer.Config, term Terminal, rootfs, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) { - return -1, ErrUnsupported -} - -func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syncPipe *SyncPipe, args []string) error { - return ErrUnsupported -} - -func InitializeNetworking(container *libcontainer.Config, nspid int, pipe *SyncPipe) error { - return ErrUnsupported -} - -func SetupCgroups(container *libcontainer.Config, nspid int) (cgroups.ActiveCgroup, error) { - return nil, ErrUnsupported -} - -func GetNamespaceFlags(namespaces map[string]bool) (flag int) { - return 0 -} diff --git a/vendor/src/github.com/docker/libcontainer/network/loopback.go b/vendor/src/github.com/docker/libcontainer/network/loopback.go index 46a1fa8c8..1667b4d82 100644 --- a/vendor/src/github.com/docker/libcontainer/network/loopback.go +++ b/vendor/src/github.com/docker/libcontainer/network/loopback.go @@ -15,9 +15,7 @@ func (l *Loopback) Create(n *Network, nspid int, networkState *NetworkState) err } func (l *Loopback) Initialize(config *Network, networkState *NetworkState) error { - if err := SetMtu("lo", config.Mtu); err != nil { - return fmt.Errorf("set lo mtu to %d %s", config.Mtu, err) - } + // Do not set the MTU on the loopback interface - use the default. if err := InterfaceUp("lo"); err != nil { return fmt.Errorf("lo up %s", err) } diff --git a/vendor/src/github.com/docker/libcontainer/network/netns.go b/vendor/src/github.com/docker/libcontainer/network/netns.go index 64544476b..1ff750645 100644 --- a/vendor/src/github.com/docker/libcontainer/network/netns.go +++ b/vendor/src/github.com/docker/libcontainer/network/netns.go @@ -7,7 +7,7 @@ import ( "os" "syscall" - "github.com/dotcloud/docker/pkg/system" + "github.com/docker/libcontainer/system" ) // crosbymichael: could make a network strategy that instead of returning veth pair names it returns a pid to an existing network namespace @@ -23,12 +23,15 @@ func (v *NetNS) Initialize(config *Network, networkState *NetworkState) error { if networkState.NsPath == "" { return fmt.Errorf("nspath does is not specified in NetworkState") } + f, err := os.OpenFile(networkState.NsPath, os.O_RDONLY, 0) if err != nil { return fmt.Errorf("failed get network namespace fd: %v", err) } + if err := system.Setns(f.Fd(), syscall.CLONE_NEWNET); err != nil { return fmt.Errorf("failed to setns current network namespace: %v", err) } + return nil } diff --git a/vendor/src/github.com/docker/libcontainer/network/types.go b/vendor/src/github.com/docker/libcontainer/network/types.go index 0f1df30e8..3b7a4e395 100644 --- a/vendor/src/github.com/docker/libcontainer/network/types.go +++ b/vendor/src/github.com/docker/libcontainer/network/types.go @@ -25,6 +25,7 @@ type Network struct { // Mtu sets the mtu value for the interface and will be mirrored on both the host and // container's interfaces if a pair is created, specifically in the case of type veth + // Note: This does not apply to loopback interfaces. Mtu int `json:"mtu,omitempty"` } diff --git a/vendor/src/github.com/docker/libcontainer/nsinit/exec.go b/vendor/src/github.com/docker/libcontainer/nsinit/exec.go index eb734545b..690af5f5e 100644 --- a/vendor/src/github.com/docker/libcontainer/nsinit/exec.go +++ b/vendor/src/github.com/docker/libcontainer/nsinit/exec.go @@ -2,14 +2,18 @@ package nsinit import ( "fmt" + "io" "log" "os" "os/exec" "os/signal" + "syscall" "github.com/codegangsta/cli" "github.com/docker/libcontainer" + consolepkg "github.com/docker/libcontainer/console" "github.com/docker/libcontainer/namespaces" + "github.com/dotcloud/docker/pkg/term" ) var execCommand = cli.Command{ @@ -34,8 +38,7 @@ func execAction(context *cli.Context) { if state != nil { err = namespaces.ExecIn(container, state, []string(context.Args())) } else { - term := namespaces.NewTerminal(os.Stdin, os.Stdout, os.Stderr, container.Tty) - exitCode, err = startContainer(container, term, dataPath, []string(context.Args())) + exitCode, err = startContainer(container, dataPath, []string(context.Args())) } if err != nil { @@ -49,7 +52,7 @@ func execAction(context *cli.Context) { // error. // // Signals sent to the current process will be forwarded to container. -func startContainer(container *libcontainer.Config, term namespaces.Terminal, dataPath string, args []string) (int, error) { +func startContainer(container *libcontainer.Config, dataPath string, args []string) (int, error) { var ( cmd *exec.Cmd sigc = make(chan os.Signal, 10) @@ -65,13 +68,66 @@ func startContainer(container *libcontainer.Config, term namespaces.Terminal, da return cmd } + var ( + master *os.File + console string + err error + + stdin = os.Stdin + stdout = os.Stdout + stderr = os.Stderr + ) + + if container.Tty { + stdin = nil + stdout = nil + stderr = nil + + master, console, err = consolepkg.CreateMasterAndConsole() + if err != nil { + return -1, err + } + + go io.Copy(master, os.Stdin) + go io.Copy(os.Stdout, master) + + state, err := term.SetRawTerminal(os.Stdin.Fd()) + if err != nil { + return -1, err + } + + defer term.RestoreTerminal(os.Stdin.Fd(), state) + } + startCallback := func() { go func() { + resizeTty(master) + for sig := range sigc { - cmd.Process.Signal(sig) + switch sig { + case syscall.SIGWINCH: + resizeTty(master) + default: + cmd.Process.Signal(sig) + } } }() } - return namespaces.Exec(container, term, "", dataPath, args, createCommand, startCallback) + return namespaces.Exec(container, stdin, stdout, stderr, console, "", dataPath, args, createCommand, startCallback) +} + +func resizeTty(master *os.File) { + if master == nil { + return + } + + ws, err := term.GetWinsize(os.Stdin.Fd()) + if err != nil { + return + } + + if err := term.SetWinsize(master.Fd(), ws); err != nil { + return + } } diff --git a/vendor/src/github.com/docker/libcontainer/security/restrict/restrict.go b/vendor/src/github.com/docker/libcontainer/security/restrict/restrict.go index ff7ae2fec..dd765b1f1 100644 --- a/vendor/src/github.com/docker/libcontainer/security/restrict/restrict.go +++ b/vendor/src/github.com/docker/libcontainer/security/restrict/restrict.go @@ -7,23 +7,21 @@ import ( "os" "syscall" "time" - - "github.com/dotcloud/docker/pkg/system" ) const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV func mountReadonly(path string) error { for i := 0; i < 5; i++ { - if err := system.Mount("", path, "", syscall.MS_REMOUNT|syscall.MS_RDONLY, ""); err != nil && !os.IsNotExist(err) { + if err := syscall.Mount("", path, "", syscall.MS_REMOUNT|syscall.MS_RDONLY, ""); err != nil && !os.IsNotExist(err) { switch err { case syscall.EINVAL: // Probably not a mountpoint, use bind-mount - if err := system.Mount(path, path, "", syscall.MS_BIND, ""); err != nil { + if err := syscall.Mount(path, path, "", syscall.MS_BIND, ""); err != nil { return err } - return system.Mount(path, path, "", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_REC|defaultMountFlags, "") + return syscall.Mount(path, path, "", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_REC|defaultMountFlags, "") case syscall.EBUSY: time.Sleep(100 * time.Millisecond) continue @@ -47,7 +45,7 @@ func Restrict(mounts ...string) error { } } - if err := system.Mount("/dev/null", "/proc/kcore", "", syscall.MS_BIND, ""); err != nil && !os.IsNotExist(err) { + if err := syscall.Mount("/dev/null", "/proc/kcore", "", syscall.MS_BIND, ""); err != nil && !os.IsNotExist(err) { return fmt.Errorf("unable to bind-mount /dev/null over /proc/kcore: %s", err) } diff --git a/vendor/src/github.com/docker/libcontainer/selinux/selinux.go b/vendor/src/github.com/docker/libcontainer/selinux/selinux.go index 709eb9d81..8dbdbdbc2 100644 --- a/vendor/src/github.com/docker/libcontainer/selinux/selinux.go +++ b/vendor/src/github.com/docker/libcontainer/selinux/selinux.go @@ -5,8 +5,6 @@ import ( "crypto/rand" "encoding/binary" "fmt" - "github.com/dotcloud/docker/pkg/mount" - "github.com/dotcloud/docker/pkg/system" "io" "os" "path/filepath" @@ -14,6 +12,9 @@ import ( "strconv" "strings" "syscall" + + "github.com/docker/libcontainer/system" + "github.com/dotcloud/docker/pkg/mount" ) const ( @@ -153,16 +154,16 @@ func Getfilecon(path string) (string, error) { } func Setfscreatecon(scon string) error { - return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", system.Gettid()), scon) + return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", syscall.Gettid()), scon) } func Getfscreatecon() (string, error) { - return readCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", system.Gettid())) + return readCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", syscall.Gettid())) } // Return the SELinux label of the current process thread. func Getcon() (string, error) { - return readCon(fmt.Sprintf("/proc/self/task/%d/attr/current", system.Gettid())) + return readCon(fmt.Sprintf("/proc/self/task/%d/attr/current", syscall.Gettid())) } func Getpidcon(pid int) (string, error) { @@ -192,7 +193,7 @@ func writeCon(name string, val string) error { } func Setexeccon(scon string) error { - return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", system.Gettid()), scon) + return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), scon) } func (c SELinuxContext) Get() string { diff --git a/vendor/src/github.com/docker/libcontainer/system/linux.go b/vendor/src/github.com/docker/libcontainer/system/linux.go new file mode 100644 index 000000000..c07ef1532 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/system/linux.go @@ -0,0 +1,60 @@ +// +build linux + +package system + +import ( + "os/exec" + "syscall" + "unsafe" +) + +func Execv(cmd string, args []string, env []string) error { + name, err := exec.LookPath(cmd) + if err != nil { + return err + } + + return syscall.Exec(name, args, env) +} + +func ParentDeathSignal(sig uintptr) error { + if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_PDEATHSIG, sig, 0); err != 0 { + return err + } + return nil +} + +func GetParentDeathSignal() (int, error) { + var sig int + + _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_GET_PDEATHSIG, uintptr(unsafe.Pointer(&sig)), 0) + + if err != 0 { + return -1, err + } + + return sig, nil +} + +func SetKeepCaps() error { + if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_KEEPCAPS, 1, 0); err != 0 { + return err + } + + return nil +} + +func ClearKeepCaps() error { + if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_KEEPCAPS, 0, 0); err != 0 { + return err + } + + return nil +} + +func Setctty() error { + if _, _, err := syscall.RawSyscall(syscall.SYS_IOCTL, 0, uintptr(syscall.TIOCSCTTY), 0); err != 0 { + return err + } + return nil +} diff --git a/vendor/src/github.com/docker/libcontainer/system/proc.go b/vendor/src/github.com/docker/libcontainer/system/proc.go new file mode 100644 index 000000000..37808a29f --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/system/proc.go @@ -0,0 +1,27 @@ +package system + +import ( + "io/ioutil" + "path/filepath" + "strconv" + "strings" +) + +// look in /proc to find the process start time so that we can verify +// that this pid has started after ourself +func GetProcessStartTime(pid int) (string, error) { + data, err := ioutil.ReadFile(filepath.Join("/proc", strconv.Itoa(pid), "stat")) + if err != nil { + return "", err + } + + parts := strings.Split(string(data), " ") + // the starttime is located at pos 22 + // from the man page + // + // starttime %llu (was %lu before Linux 2.6) + // (22) The time the process started after system boot. In kernels before Linux 2.6, this + // value was expressed in jiffies. Since Linux 2.6, the value is expressed in clock ticks + // (divide by sysconf(_SC_CLK_TCK)). + return parts[22-1], nil // starts at 1 +} diff --git a/vendor/src/github.com/docker/libcontainer/system/setns_linux.go b/vendor/src/github.com/docker/libcontainer/system/setns_linux.go new file mode 100644 index 000000000..a0a259e17 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/system/setns_linux.go @@ -0,0 +1,29 @@ +package system + +import ( + "fmt" + "runtime" + "syscall" +) + +// Via http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=7b21fddd087678a70ad64afc0f632e0f1071b092 +// +// We need different setns values for the different platforms and arch +// We are declaring the macro here because the SETNS syscall does not exist in th stdlib +var setNsMap = map[string]uintptr{ + "linux/amd64": 308, +} + +func Setns(fd uintptr, flags uintptr) error { + ns, exists := setNsMap[fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)] + if !exists { + return fmt.Errorf("unsupported platform %s/%s", runtime.GOOS, runtime.GOARCH) + } + + _, _, err := syscall.RawSyscall(ns, fd, flags, 0) + if err != 0 { + return err + } + + return nil +} diff --git a/vendor/src/github.com/docker/libcontainer/system/sysconfig.go b/vendor/src/github.com/docker/libcontainer/system/sysconfig.go new file mode 100644 index 000000000..dcbe6c9cd --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/system/sysconfig.go @@ -0,0 +1,13 @@ +// +build linux,cgo + +package system + +/* +#include +int get_hz(void) { return sysconf(_SC_CLK_TCK); } +*/ +import "C" + +func GetClockTicks() int { + return int(C.get_hz()) +} diff --git a/vendor/src/github.com/docker/libcontainer/system/xattrs_linux.go b/vendor/src/github.com/docker/libcontainer/system/xattrs_linux.go new file mode 100644 index 000000000..00edb201b --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/system/xattrs_linux.go @@ -0,0 +1,59 @@ +package system + +import ( + "syscall" + "unsafe" +) + +// Returns a nil slice and nil error if the xattr is not set +func Lgetxattr(path string, attr string) ([]byte, error) { + pathBytes, err := syscall.BytePtrFromString(path) + if err != nil { + return nil, err + } + attrBytes, err := syscall.BytePtrFromString(attr) + if err != nil { + return nil, err + } + + dest := make([]byte, 128) + destBytes := unsafe.Pointer(&dest[0]) + sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) + if errno == syscall.ENODATA { + return nil, nil + } + if errno == syscall.ERANGE { + dest = make([]byte, sz) + destBytes := unsafe.Pointer(&dest[0]) + sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) + } + if errno != 0 { + return nil, errno + } + + return dest[:sz], nil +} + +var _zero uintptr + +func Lsetxattr(path string, attr string, data []byte, flags int) error { + pathBytes, err := syscall.BytePtrFromString(path) + if err != nil { + return err + } + attrBytes, err := syscall.BytePtrFromString(attr) + if err != nil { + return err + } + var dataBytes unsafe.Pointer + if len(data) > 0 { + dataBytes = unsafe.Pointer(&data[0]) + } else { + dataBytes = unsafe.Pointer(&_zero) + } + _, _, errno := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(dataBytes), uintptr(len(data)), uintptr(flags), 0) + if errno != 0 { + return errno + } + return nil +} From 1501c342d815e3a128dac393b69e23f6ec39c2d7 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Tue, 15 Jul 2014 18:31:46 -0700 Subject: [PATCH 2/4] Don't create pty slave in the daemon for native driver Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- daemon/execdriver/native/driver.go | 27 +++++++------------ daemon/execdriver/native/term.go | 42 ------------------------------ daemon/execdriver/termconsole.go | 26 +++++++++--------- pkg/system/sysconfig.go | 13 --------- 4 files changed, 22 insertions(+), 86 deletions(-) delete mode 100644 daemon/execdriver/native/term.go delete mode 100644 pkg/system/sysconfig.go diff --git a/daemon/execdriver/native/driver.go b/daemon/execdriver/native/driver.go index 3f2036b8c..5b1b96bdf 100644 --- a/daemon/execdriver/native/driver.go +++ b/daemon/execdriver/native/driver.go @@ -95,6 +95,11 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba if err != nil { return -1, err } + + if err := execdriver.SetTerminal(c, pipes); err != nil { + return -1, err + } + d.Lock() d.activeContainers[c.ID] = &activeContainer{ container: container, @@ -106,6 +111,7 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba dataPath = filepath.Join(d.root, c.ID) args = append([]string{c.Entrypoint}, c.Arguments...) ) + if err := d.createContainerRoot(c.ID); err != nil { return -1, err } @@ -115,9 +121,7 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba return -1, err } - term := getTerminal(c, pipes) - - return namespaces.Exec(container, term, c.Rootfs, dataPath, args, func(container *libcontainer.Config, console, rootfs, dataPath, init string, child *os.File, args []string) *exec.Cmd { + return namespaces.Exec(container, c.Stdin, c.Stdout, c.Stderr, c.Console, c.Rootfs, dataPath, args, func(container *libcontainer.Config, console, rootfs, dataPath, init string, child *os.File, args []string) *exec.Cmd { // we need to join the rootfs because namespaces will setup the rootfs and chroot initPath := filepath.Join(c.Rootfs, c.InitPath) @@ -201,11 +205,13 @@ func (d *driver) Terminate(p *execdriver.Command) error { if err != nil { return err } + if state.InitStartTime == currentStartTime { err = syscall.Kill(p.Process.Pid, 9) syscall.Wait4(p.Process.Pid, nil, 0, nil) } d.removeContainerRoot(p.ID) + return err } @@ -266,18 +272,3 @@ func getEnv(key string, env []string) string { } return "" } - -func getTerminal(c *execdriver.Command, pipes *execdriver.Pipes) namespaces.Terminal { - var term namespaces.Terminal - if c.Tty { - term = &dockerTtyTerm{ - pipes: pipes, - } - } else { - term = &dockerStdTerm{ - pipes: pipes, - } - } - c.Terminal = term - return term -} diff --git a/daemon/execdriver/native/term.go b/daemon/execdriver/native/term.go deleted file mode 100644 index f60351c60..000000000 --- a/daemon/execdriver/native/term.go +++ /dev/null @@ -1,42 +0,0 @@ -/* - These types are wrappers around the libcontainer Terminal interface so that - we can resuse the docker implementations where possible. -*/ -package native - -import ( - "github.com/dotcloud/docker/daemon/execdriver" - "io" - "os" - "os/exec" -) - -type dockerStdTerm struct { - execdriver.StdConsole - pipes *execdriver.Pipes -} - -func (d *dockerStdTerm) Attach(cmd *exec.Cmd) error { - return d.AttachPipes(cmd, d.pipes) -} - -func (d *dockerStdTerm) SetMaster(master *os.File) { - // do nothing -} - -type dockerTtyTerm struct { - execdriver.TtyConsole - pipes *execdriver.Pipes -} - -func (t *dockerTtyTerm) Attach(cmd *exec.Cmd) error { - go io.Copy(t.pipes.Stdout, t.MasterPty) - if t.pipes.Stdin != nil { - go io.Copy(t.MasterPty, t.pipes.Stdin) - } - return nil -} - -func (t *dockerTtyTerm) SetMaster(master *os.File) { - t.MasterPty = master -} diff --git a/daemon/execdriver/termconsole.go b/daemon/execdriver/termconsole.go index af6b88d3d..ebd849209 100644 --- a/daemon/execdriver/termconsole.go +++ b/daemon/execdriver/termconsole.go @@ -1,11 +1,12 @@ package execdriver import ( - "github.com/dotcloud/docker/pkg/term" - "github.com/kr/pty" "io" "os" "os/exec" + + "github.com/dotcloud/docker/pkg/system" + "github.com/dotcloud/docker/pkg/term" ) func SetTerminal(command *Command, pipes *Pipes) error { @@ -13,37 +14,42 @@ func SetTerminal(command *Command, pipes *Pipes) error { term Terminal err error ) + if command.Tty { term, err = NewTtyConsole(command, pipes) } else { term, err = NewStdConsole(command, pipes) } + if err != nil { return err } + command.Terminal = term + return nil } type TtyConsole struct { MasterPty *os.File - SlavePty *os.File } func NewTtyConsole(command *Command, pipes *Pipes) (*TtyConsole, error) { - ptyMaster, ptySlave, err := pty.Open() + ptyMaster, console, err := system.CreateMasterAndConsole() if err != nil { return nil, err } + tty := &TtyConsole{ MasterPty: ptyMaster, - SlavePty: ptySlave, } + if err := tty.AttachPipes(&command.Cmd, pipes); err != nil { tty.Close() return nil, err } - command.Console = tty.SlavePty.Name() + command.Console = console + return tty, nil } @@ -56,9 +62,6 @@ func (t *TtyConsole) Resize(h, w int) error { } func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *Pipes) error { - command.Stdout = t.SlavePty - command.Stderr = t.SlavePty - go func() { if wb, ok := pipes.Stdout.(interface { CloseWriters() error @@ -69,19 +72,16 @@ func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *Pipes) error { }() if pipes.Stdin != nil { - command.Stdin = t.SlavePty - command.SysProcAttr.Setctty = true - go func() { defer pipes.Stdin.Close() io.Copy(t.MasterPty, pipes.Stdin) }() } + return nil } func (t *TtyConsole) Close() error { - t.SlavePty.Close() return t.MasterPty.Close() } diff --git a/pkg/system/sysconfig.go b/pkg/system/sysconfig.go deleted file mode 100644 index dcbe6c9cd..000000000 --- a/pkg/system/sysconfig.go +++ /dev/null @@ -1,13 +0,0 @@ -// +build linux,cgo - -package system - -/* -#include -int get_hz(void) { return sysconf(_SC_CLK_TCK); } -*/ -import "C" - -func GetClockTicks() int { - return int(C.get_hz()) -} From 0d67b420b59c953cf331f735e49e7acad742a41f Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Wed, 16 Jul 2014 15:37:10 -0700 Subject: [PATCH 3/4] Make tty term exec driver specific lxc is special in that we cannot create the master outside of the container without opening the slave because we have nothing to provide to the cmd. We have to open both then do the crazy setup on command right now instead of passing the console path to lxc and telling it to open up that console. we save a couple of openfiles in the native driver because we can do this. Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- daemon/execdriver/lxc/driver.go | 88 +++++++++++++++++++++++++++++- daemon/execdriver/native/driver.go | 69 ++++++++++++++++++++++- daemon/execdriver/termconsole.go | 80 --------------------------- 3 files changed, 153 insertions(+), 84 deletions(-) diff --git a/daemon/execdriver/lxc/driver.go b/daemon/execdriver/lxc/driver.go index 5a6055fc4..fe3a3ce22 100644 --- a/daemon/execdriver/lxc/driver.go +++ b/daemon/execdriver/lxc/driver.go @@ -3,6 +3,7 @@ package lxc import ( "encoding/json" "fmt" + "io" "io/ioutil" "log" "os" @@ -19,7 +20,9 @@ import ( "github.com/docker/libcontainer/label" "github.com/docker/libcontainer/mount/nodes" "github.com/dotcloud/docker/daemon/execdriver" + "github.com/dotcloud/docker/pkg/term" "github.com/dotcloud/docker/utils" + "github.com/kr/pty" ) const DriverName = "lxc" @@ -78,10 +81,20 @@ func (d *driver) Name() string { } func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) { - if err := execdriver.SetTerminal(c, pipes); err != nil { - return -1, err + var ( + term execdriver.Terminal + err error + ) + + if c.Tty { + term, err = NewTtyConsole(c, pipes) + } else { + term, err = execdriver.NewStdConsole(c, pipes) } + c.Terminal = term + c.Mounts = append(c.Mounts, execdriver.Mount{d.initPath, c.InitPath, false, true}) + if err := d.generateEnvConfig(c); err != nil { return -1, err } @@ -462,3 +475,74 @@ func (d *driver) generateEnvConfig(c *execdriver.Command) error { return ioutil.WriteFile(p, data, 0600) } + +type TtyConsole struct { + MasterPty *os.File + SlavePty *os.File +} + +func NewTtyConsole(command *execdriver.Command, pipes *execdriver.Pipes) (*TtyConsole, error) { + // lxc is special in that we cannot create the master outside of the container without + // opening the slave because we have nothing to provide to the cmd. We have to open both then do + // the crazy setup on command right now instead of passing the console path to lxc and telling it + // to open up that console. we save a couple of openfiles in the native driver because we can do + // this. + ptyMaster, ptySlave, err := pty.Open() + if err != nil { + return nil, err + } + + tty := &TtyConsole{ + MasterPty: ptyMaster, + SlavePty: ptySlave, + } + + if err := tty.AttachPipes(&command.Cmd, pipes); err != nil { + tty.Close() + return nil, err + } + + command.Console = tty.SlavePty.Name() + + return tty, nil +} + +func (t *TtyConsole) Master() *os.File { + return t.MasterPty +} + +func (t *TtyConsole) Resize(h, w int) error { + return term.SetWinsize(t.MasterPty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)}) +} + +func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *execdriver.Pipes) error { + command.Stdout = t.SlavePty + command.Stderr = t.SlavePty + + go func() { + if wb, ok := pipes.Stdout.(interface { + CloseWriters() error + }); ok { + defer wb.CloseWriters() + } + + io.Copy(pipes.Stdout, t.MasterPty) + }() + + if pipes.Stdin != nil { + command.Stdin = t.SlavePty + command.SysProcAttr.Setctty = true + + go func() { + io.Copy(t.MasterPty, pipes.Stdin) + + pipes.Stdin.Close() + }() + } + return nil +} + +func (t *TtyConsole) Close() error { + t.SlavePty.Close() + return t.MasterPty.Close() +} diff --git a/daemon/execdriver/native/driver.go b/daemon/execdriver/native/driver.go index 5b1b96bdf..711f29429 100644 --- a/daemon/execdriver/native/driver.go +++ b/daemon/execdriver/native/driver.go @@ -5,6 +5,7 @@ package native import ( "encoding/json" "fmt" + "io" "io/ioutil" "os" "os/exec" @@ -21,6 +22,7 @@ import ( "github.com/docker/libcontainer/syncpipe" "github.com/dotcloud/docker/daemon/execdriver" "github.com/dotcloud/docker/pkg/system" + "github.com/dotcloud/docker/pkg/term" ) const ( @@ -96,9 +98,14 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba return -1, err } - if err := execdriver.SetTerminal(c, pipes); err != nil { - return -1, err + var term execdriver.Terminal + + if c.Tty { + term, err = NewTtyConsole(c, pipes) + } else { + term, err = execdriver.NewStdConsole(c, pipes) } + c.Terminal = term d.Lock() d.activeContainers[c.ID] = &activeContainer{ @@ -272,3 +279,61 @@ func getEnv(key string, env []string) string { } return "" } + +type TtyConsole struct { + MasterPty *os.File +} + +func NewTtyConsole(command *execdriver.Command, pipes *execdriver.Pipes) (*TtyConsole, error) { + ptyMaster, console, err := system.CreateMasterAndConsole() + if err != nil { + return nil, err + } + + tty := &TtyConsole{ + MasterPty: ptyMaster, + } + + if err := tty.AttachPipes(&command.Cmd, pipes); err != nil { + tty.Close() + return nil, err + } + + command.Console = console + + return tty, nil +} + +func (t *TtyConsole) Master() *os.File { + return t.MasterPty +} + +func (t *TtyConsole) Resize(h, w int) error { + return term.SetWinsize(t.MasterPty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)}) +} + +func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *execdriver.Pipes) error { + go func() { + if wb, ok := pipes.Stdout.(interface { + CloseWriters() error + }); ok { + defer wb.CloseWriters() + } + + io.Copy(pipes.Stdout, t.MasterPty) + }() + + if pipes.Stdin != nil { + go func() { + io.Copy(t.MasterPty, pipes.Stdin) + + pipes.Stdin.Close() + }() + } + + return nil +} + +func (t *TtyConsole) Close() error { + return t.MasterPty.Close() +} diff --git a/daemon/execdriver/termconsole.go b/daemon/execdriver/termconsole.go index ebd849209..dc0e54ccd 100644 --- a/daemon/execdriver/termconsole.go +++ b/daemon/execdriver/termconsole.go @@ -2,89 +2,9 @@ package execdriver import ( "io" - "os" "os/exec" - - "github.com/dotcloud/docker/pkg/system" - "github.com/dotcloud/docker/pkg/term" ) -func SetTerminal(command *Command, pipes *Pipes) error { - var ( - term Terminal - err error - ) - - if command.Tty { - term, err = NewTtyConsole(command, pipes) - } else { - term, err = NewStdConsole(command, pipes) - } - - if err != nil { - return err - } - - command.Terminal = term - - return nil -} - -type TtyConsole struct { - MasterPty *os.File -} - -func NewTtyConsole(command *Command, pipes *Pipes) (*TtyConsole, error) { - ptyMaster, console, err := system.CreateMasterAndConsole() - if err != nil { - return nil, err - } - - tty := &TtyConsole{ - MasterPty: ptyMaster, - } - - if err := tty.AttachPipes(&command.Cmd, pipes); err != nil { - tty.Close() - return nil, err - } - command.Console = console - - return tty, nil -} - -func (t *TtyConsole) Master() *os.File { - return t.MasterPty -} - -func (t *TtyConsole) Resize(h, w int) error { - return term.SetWinsize(t.MasterPty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)}) -} - -func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *Pipes) error { - go func() { - if wb, ok := pipes.Stdout.(interface { - CloseWriters() error - }); ok { - defer wb.CloseWriters() - } - io.Copy(pipes.Stdout, t.MasterPty) - }() - - if pipes.Stdin != nil { - go func() { - defer pipes.Stdin.Close() - io.Copy(t.MasterPty, pipes.Stdin) - }() - } - - return nil -} - -func (t *TtyConsole) Close() error { - return t.MasterPty.Close() -} - type StdConsole struct { } From 7a8ea91392e0cc97caf2a6edc3b262b33a5b446d Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Wed, 16 Jul 2014 16:39:15 -0700 Subject: [PATCH 4/4] Fix cross compile non cgo and linux systems Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- daemon/daemon.go | 6 +++--- daemon/execdriver/native/create.go | 2 +- daemon/execdriver/native/driver.go | 2 +- .../execdriver/native/driver_unsupported_nocgo.go | 13 +++++++++++++ daemon/execdriver/native/info.go | 2 +- daemon/utils_linux.go | 13 +++++++++++++ daemon/utils_nolinux.go | 9 +++++++++ 7 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 daemon/execdriver/native/driver_unsupported_nocgo.go create mode 100644 daemon/utils_linux.go create mode 100644 daemon/utils_nolinux.go diff --git a/daemon/daemon.go b/daemon/daemon.go index c45b8b9d3..d3f73f413 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -13,7 +13,6 @@ import ( "time" "github.com/docker/libcontainer/label" - "github.com/docker/libcontainer/selinux" "github.com/dotcloud/docker/archive" "github.com/dotcloud/docker/daemon/execdriver" "github.com/dotcloud/docker/daemon/execdriver/execdrivers" @@ -300,7 +299,8 @@ func (daemon *Daemon) Destroy(container *Container) error { if err := os.RemoveAll(container.root); err != nil { return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err) } - selinux.FreeLxcContexts(container.ProcessLabel) + + selinuxFreeLxcContexts(container.ProcessLabel) return nil } @@ -761,7 +761,7 @@ func NewDaemon(config *daemonconfig.Config, eng *engine.Engine) (*Daemon, error) func NewDaemonFromDirectory(config *daemonconfig.Config, eng *engine.Engine) (*Daemon, error) { if !config.EnableSelinuxSupport { - selinux.SetDisabled() + selinuxSetDisabled() } // Create the root directory if it doesn't exists diff --git a/daemon/execdriver/native/create.go b/daemon/execdriver/native/create.go index a96270d8b..280ad70a6 100644 --- a/daemon/execdriver/native/create.go +++ b/daemon/execdriver/native/create.go @@ -1,4 +1,4 @@ -// +build linux +// +build linux,cgo package native diff --git a/daemon/execdriver/native/driver.go b/daemon/execdriver/native/driver.go index 711f29429..37c21d6f9 100644 --- a/daemon/execdriver/native/driver.go +++ b/daemon/execdriver/native/driver.go @@ -1,4 +1,4 @@ -// +build linux +// +build linux,cgo package native diff --git a/daemon/execdriver/native/driver_unsupported_nocgo.go b/daemon/execdriver/native/driver_unsupported_nocgo.go new file mode 100644 index 000000000..997909938 --- /dev/null +++ b/daemon/execdriver/native/driver_unsupported_nocgo.go @@ -0,0 +1,13 @@ +// +build linux,!cgo + +package native + +import ( + "fmt" + + "github.com/dotcloud/docker/daemon/execdriver" +) + +func NewDriver(root, initPath string) (execdriver.Driver, error) { + return nil, fmt.Errorf("native driver not supported on non-linux") +} diff --git a/daemon/execdriver/native/info.go b/daemon/execdriver/native/info.go index a27d5640a..601b97e81 100644 --- a/daemon/execdriver/native/info.go +++ b/daemon/execdriver/native/info.go @@ -1,4 +1,4 @@ -// +build linux +// +build linux,cgo package native diff --git a/daemon/utils_linux.go b/daemon/utils_linux.go new file mode 100644 index 000000000..bff2a787b --- /dev/null +++ b/daemon/utils_linux.go @@ -0,0 +1,13 @@ +// +build linux + +package daemon + +import "github.com/docker/libcontainer/selinux" + +func selinuxSetDisabled() { + selinux.SetDisabled() +} + +func selinuxFreeLxcContexts(label string) { + selinux.FreeLxcContexts(label) +} diff --git a/daemon/utils_nolinux.go b/daemon/utils_nolinux.go new file mode 100644 index 000000000..399376dbd --- /dev/null +++ b/daemon/utils_nolinux.go @@ -0,0 +1,9 @@ +// +build !linux + +package daemon + +func selinuxSetDisabled() { +} + +func selinuxFreeLxcContexts(label string) { +}