зеркало из https://github.com/microsoft/docker.git
Update libcontainer to be85764f109c3f0f62cd2a5c8be
Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@docker.com> (github: crosbymichael)
This commit is contained in:
Родитель
6cd1061a5b
Коммит
9fc6058aa1
|
@ -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/godbus/dbus v1
|
||||||
clone git github.com/coreos/go-systemd v2
|
clone git github.com/coreos/go-systemd v2
|
||||||
clone git github.com/docker/libcontainer fb67bb80b4205bece36ff7096ee745ab0cee7e06
|
clone git github.com/docker/libcontainer be85764f109c3f0f62cd2a5c8be9af7a599798cf
|
||||||
|
|
|
@ -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"]
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/libcontainer/cgroups"
|
"github.com/docker/libcontainer/cgroups"
|
||||||
"github.com/dotcloud/docker/pkg/system"
|
"github.com/docker/libcontainer/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -7,22 +7,24 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/docker/libcontainer/label"
|
"github.com/docker/libcontainer/label"
|
||||||
"github.com/dotcloud/docker/pkg/system"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Setup initializes the proper /dev/console inside the rootfs path
|
// Setup initializes the proper /dev/console inside the rootfs path
|
||||||
func Setup(rootfs, consolePath, mountLabel string) error {
|
func Setup(rootfs, consolePath, mountLabel string) error {
|
||||||
oldMask := system.Umask(0000)
|
oldMask := syscall.Umask(0000)
|
||||||
defer system.Umask(oldMask)
|
defer syscall.Umask(oldMask)
|
||||||
|
|
||||||
if err := os.Chmod(consolePath, 0600); err != nil {
|
if err := os.Chmod(consolePath, 0600); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.Chown(consolePath, 0, 0); err != nil {
|
if err := os.Chown(consolePath, 0, 0); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := label.SetFileLabel(consolePath, mountLabel); err != nil {
|
if err := label.SetFileLabel(consolePath, mountLabel); err != nil {
|
||||||
return fmt.Errorf("set file label %s %s", consolePath, err)
|
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) {
|
if err != nil && !os.IsExist(err) {
|
||||||
return fmt.Errorf("create %s %s", dest, err)
|
return fmt.Errorf("create %s %s", dest, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if f != nil {
|
if f != nil {
|
||||||
f.Close()
|
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 fmt.Errorf("bind %s to %s %s", consolePath, dest, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func OpenAndDup(consolePath string) error {
|
func OpenAndDup(consolePath string) error {
|
||||||
slave, err := system.OpenTerminal(consolePath, syscall.O_RDWR)
|
slave, err := OpenTerminal(consolePath, syscall.O_RDWR)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("open terminal %s", err)
|
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
|
return err
|
||||||
}
|
}
|
||||||
if err := system.Dup2(slave.Fd(), 1); err != nil {
|
|
||||||
|
if err := syscall.Dup2(int(slave.Fd()), 1); err != nil {
|
||||||
return err
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"github.com/docker/libcontainer/label"
|
"github.com/docker/libcontainer/label"
|
||||||
"github.com/docker/libcontainer/mount/nodes"
|
"github.com/docker/libcontainer/mount/nodes"
|
||||||
"github.com/dotcloud/docker/pkg/symlink"
|
"github.com/dotcloud/docker/pkg/symlink"
|
||||||
"github.com/dotcloud/docker/pkg/system"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// default mount point flags
|
// default mount point flags
|
||||||
|
@ -35,10 +34,10 @@ func InitializeMountNamespace(rootfs, console string, mountConfig *MountConfig)
|
||||||
if mountConfig.NoPivotRoot {
|
if mountConfig.NoPivotRoot {
|
||||||
flag = syscall.MS_SLAVE
|
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)
|
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)
|
return fmt.Errorf("mouting %s as bind %s", rootfs, err)
|
||||||
}
|
}
|
||||||
if err := mountSystem(rootfs, mountConfig); err != nil {
|
if err := mountSystem(rootfs, mountConfig); err != nil {
|
||||||
|
@ -56,7 +55,7 @@ func InitializeMountNamespace(rootfs, console string, mountConfig *MountConfig)
|
||||||
if err := setupDevSymlinks(rootfs); err != nil {
|
if err := setupDevSymlinks(rootfs); err != nil {
|
||||||
return fmt.Errorf("dev symlinks %s", err)
|
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)
|
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
|
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) {
|
if err := os.MkdirAll(m.path, 0755); err != nil && !os.IsExist(err) {
|
||||||
return fmt.Errorf("mkdirall %s %s", m.path, 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)
|
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)
|
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)
|
return fmt.Errorf("mounting %s into %s %s", m.Source, dest, err)
|
||||||
}
|
}
|
||||||
if !m.Writable {
|
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)
|
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 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)
|
return fmt.Errorf("mounting %s private %s", dest, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,17 @@ package mount
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/dotcloud/docker/pkg/system"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
func MsMoveRoot(rootfs string) error {
|
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)
|
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 fmt.Errorf("chroot . %s", err)
|
||||||
}
|
}
|
||||||
return system.Chdir("/")
|
|
||||||
|
return syscall.Chdir("/")
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,12 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/docker/libcontainer/devices"
|
"github.com/docker/libcontainer/devices"
|
||||||
"github.com/dotcloud/docker/pkg/system"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create the device nodes in the container.
|
// Create the device nodes in the container.
|
||||||
func CreateDeviceNodes(rootfs string, nodesToCreate []*devices.Device) error {
|
func CreateDeviceNodes(rootfs string, nodesToCreate []*devices.Device) error {
|
||||||
oldMask := system.Umask(0000)
|
oldMask := syscall.Umask(0000)
|
||||||
defer system.Umask(oldMask)
|
defer syscall.Umask(oldMask)
|
||||||
|
|
||||||
for _, node := range nodesToCreate {
|
for _, node := range nodesToCreate {
|
||||||
if err := CreateDeviceNode(rootfs, node); err != nil {
|
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)
|
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 fmt.Errorf("mknod %s %s", node.Path, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -8,8 +8,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/dotcloud/docker/pkg/system"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func PivotRoot(rootfs string) error {
|
func PivotRoot(rootfs string) error {
|
||||||
|
@ -17,16 +15,20 @@ func PivotRoot(rootfs string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("can't create pivot_root dir %s, error %v", pivotDir, err)
|
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)
|
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)
|
return fmt.Errorf("chdir / %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// path to pivot dir now changed, update
|
// path to pivot dir now changed, update
|
||||||
pivotDir = filepath.Join("/", filepath.Base(pivotDir))
|
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 fmt.Errorf("unmount pivot_root dir %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return os.Remove(pivotDir)
|
return os.Remove(pivotDir)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,10 @@ package mount
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/docker/libcontainer/console"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/docker/libcontainer/console"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SetupPtmx(rootfs, consolePath, mountLabel string) error {
|
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) {
|
if err := os.Remove(ptmx); err != nil && !os.IsNotExist(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.Symlink("pts/ptmx", ptmx); err != nil {
|
if err := os.Symlink("pts/ptmx", ptmx); err != nil {
|
||||||
return fmt.Errorf("symlink dev ptmx %s", err)
|
return fmt.Errorf("symlink dev ptmx %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if consolePath != "" {
|
if consolePath != "" {
|
||||||
if err := console.Setup(rootfs, consolePath, mountLabel); err != nil {
|
if err := console.Setup(rootfs, consolePath, mountLabel); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,9 @@
|
||||||
package mount
|
package mount
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/dotcloud/docker/pkg/system"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SetReadonly() error {
|
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, "")
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,30 +2,30 @@
|
||||||
|
|
||||||
package mount
|
package mount
|
||||||
|
|
||||||
import (
|
import "syscall"
|
||||||
"github.com/dotcloud/docker/pkg/system"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
func RemountProc() error {
|
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
|
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 err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemountSys() error {
|
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 {
|
if err != syscall.EINVAL {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} 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 err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
package namespaces
|
package namespaces
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
@ -13,18 +14,16 @@ import (
|
||||||
"github.com/docker/libcontainer/cgroups/systemd"
|
"github.com/docker/libcontainer/cgroups/systemd"
|
||||||
"github.com/docker/libcontainer/network"
|
"github.com/docker/libcontainer/network"
|
||||||
"github.com/docker/libcontainer/syncpipe"
|
"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.
|
// TODO(vishh): This is part of the libcontainer API and it does much more than just namespaces related work.
|
||||||
// Move this to libcontainer package.
|
// Move this to libcontainer package.
|
||||||
// Exec performs setup outside of a namespace so that a container can be
|
// 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.
|
// 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 (
|
var (
|
||||||
master *os.File
|
err error
|
||||||
console string
|
|
||||||
err error
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// create a pipe so that we can syncronize with the namespaced process and
|
// 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()
|
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)
|
command := createCommand(container, console, rootfs, dataPath, os.Args[0], syncPipe.Child(), args)
|
||||||
|
// Note: these are only used in non-tty mode
|
||||||
if err := term.Attach(command); err != nil {
|
// if there is a tty for the container it will be opened within the namespace and the
|
||||||
return -1, err
|
// fds will be duped to stdin, stdiout, and stderr
|
||||||
}
|
command.Stdin = stdin
|
||||||
defer term.Close()
|
command.Stdout = stdout
|
||||||
|
command.Stderr = stderr
|
||||||
|
|
||||||
if err := command.Start(); err != nil {
|
if err := command.Start(); err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
|
@ -110,6 +102,7 @@ func Exec(container *libcontainer.Config, term Terminal, rootfs, dataPath string
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil
|
return command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +138,11 @@ func DefaultCreateCommand(container *libcontainer.Config, console, rootfs, dataP
|
||||||
command.Dir = rootfs
|
command.Dir = rootfs
|
||||||
command.Env = append(os.Environ(), env...)
|
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.SysProcAttr.Pdeathsig = syscall.SIGKILL
|
||||||
command.ExtraFiles = []*os.File{pipe}
|
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) {
|
func SetupCgroups(container *libcontainer.Config, nspid int) (cgroups.ActiveCgroup, error) {
|
||||||
if container.Cgroups != nil {
|
if container.Cgroups != nil {
|
||||||
c := container.Cgroups
|
c := container.Cgroups
|
||||||
|
|
||||||
if systemd.UseSystemd() {
|
if systemd.UseSystemd() {
|
||||||
return systemd.Apply(c, nspid)
|
return systemd.Apply(c, nspid)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fs.Apply(c, nspid)
|
return fs.Apply(c, nspid)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/docker/libcontainer"
|
"github.com/docker/libcontainer"
|
||||||
"github.com/docker/libcontainer/label"
|
"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.
|
// ExecIn uses an existing pid and joins the pid's namespaces with the new command.
|
||||||
|
|
|
@ -19,8 +19,8 @@ import (
|
||||||
"github.com/docker/libcontainer/security/capabilities"
|
"github.com/docker/libcontainer/security/capabilities"
|
||||||
"github.com/docker/libcontainer/security/restrict"
|
"github.com/docker/libcontainer/security/restrict"
|
||||||
"github.com/docker/libcontainer/syncpipe"
|
"github.com/docker/libcontainer/syncpipe"
|
||||||
|
"github.com/docker/libcontainer/system"
|
||||||
"github.com/docker/libcontainer/utils"
|
"github.com/docker/libcontainer/utils"
|
||||||
"github.com/dotcloud/docker/pkg/system"
|
|
||||||
"github.com/dotcloud/docker/pkg/user"
|
"github.com/dotcloud/docker/pkg/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syn
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, err := system.Setsid(); err != nil {
|
if _, err := syscall.Setsid(); err != nil {
|
||||||
return fmt.Errorf("setsid %s", err)
|
return fmt.Errorf("setsid %s", err)
|
||||||
}
|
}
|
||||||
if consolePath != "" {
|
if consolePath != "" {
|
||||||
|
@ -81,7 +81,7 @@ func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syn
|
||||||
}
|
}
|
||||||
|
|
||||||
if container.Hostname != "" {
|
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)
|
return fmt.Errorf("sethostname %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,15 +155,19 @@ func SetupUser(u string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("get supplementary groups %s", err)
|
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)
|
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)
|
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 fmt.Errorf("setuid %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,7 +233,7 @@ func FinalizeNamespace(container *libcontainer.Config) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if container.WorkingDir != "" {
|
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)
|
return fmt.Errorf("chdir to %s %s", container.WorkingDir, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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()
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -15,9 +15,7 @@ func (l *Loopback) Create(n *Network, nspid int, networkState *NetworkState) err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Loopback) Initialize(config *Network, networkState *NetworkState) error {
|
func (l *Loopback) Initialize(config *Network, networkState *NetworkState) error {
|
||||||
if err := SetMtu("lo", config.Mtu); err != nil {
|
// Do not set the MTU on the loopback interface - use the default.
|
||||||
return fmt.Errorf("set lo mtu to %d %s", config.Mtu, err)
|
|
||||||
}
|
|
||||||
if err := InterfaceUp("lo"); err != nil {
|
if err := InterfaceUp("lo"); err != nil {
|
||||||
return fmt.Errorf("lo up %s", err)
|
return fmt.Errorf("lo up %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"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
|
// 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 == "" {
|
if networkState.NsPath == "" {
|
||||||
return fmt.Errorf("nspath does is not specified in NetworkState")
|
return fmt.Errorf("nspath does is not specified in NetworkState")
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := os.OpenFile(networkState.NsPath, os.O_RDONLY, 0)
|
f, err := os.OpenFile(networkState.NsPath, os.O_RDONLY, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed get network namespace fd: %v", err)
|
return fmt.Errorf("failed get network namespace fd: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := system.Setns(f.Fd(), syscall.CLONE_NEWNET); err != nil {
|
if err := system.Setns(f.Fd(), syscall.CLONE_NEWNET); err != nil {
|
||||||
return fmt.Errorf("failed to setns current network namespace: %v", err)
|
return fmt.Errorf("failed to setns current network namespace: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ type Network struct {
|
||||||
|
|
||||||
// Mtu sets the mtu value for the interface and will be mirrored on both the host and
|
// 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
|
// 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"`
|
Mtu int `json:"mtu,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,18 @@ package nsinit
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
"github.com/docker/libcontainer"
|
"github.com/docker/libcontainer"
|
||||||
|
consolepkg "github.com/docker/libcontainer/console"
|
||||||
"github.com/docker/libcontainer/namespaces"
|
"github.com/docker/libcontainer/namespaces"
|
||||||
|
"github.com/dotcloud/docker/pkg/term"
|
||||||
)
|
)
|
||||||
|
|
||||||
var execCommand = cli.Command{
|
var execCommand = cli.Command{
|
||||||
|
@ -34,8 +38,7 @@ func execAction(context *cli.Context) {
|
||||||
if state != nil {
|
if state != nil {
|
||||||
err = namespaces.ExecIn(container, state, []string(context.Args()))
|
err = namespaces.ExecIn(container, state, []string(context.Args()))
|
||||||
} else {
|
} else {
|
||||||
term := namespaces.NewTerminal(os.Stdin, os.Stdout, os.Stderr, container.Tty)
|
exitCode, err = startContainer(container, dataPath, []string(context.Args()))
|
||||||
exitCode, err = startContainer(container, term, dataPath, []string(context.Args()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -49,7 +52,7 @@ func execAction(context *cli.Context) {
|
||||||
// error.
|
// error.
|
||||||
//
|
//
|
||||||
// Signals sent to the current process will be forwarded to container.
|
// 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 (
|
var (
|
||||||
cmd *exec.Cmd
|
cmd *exec.Cmd
|
||||||
sigc = make(chan os.Signal, 10)
|
sigc = make(chan os.Signal, 10)
|
||||||
|
@ -65,13 +68,66 @@ func startContainer(container *libcontainer.Config, term namespaces.Terminal, da
|
||||||
return cmd
|
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() {
|
startCallback := func() {
|
||||||
go func() {
|
go func() {
|
||||||
|
resizeTty(master)
|
||||||
|
|
||||||
for sig := range sigc {
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,23 +7,21 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dotcloud/docker/pkg/system"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV
|
const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV
|
||||||
|
|
||||||
func mountReadonly(path string) error {
|
func mountReadonly(path string) error {
|
||||||
for i := 0; i < 5; i++ {
|
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 {
|
switch err {
|
||||||
case syscall.EINVAL:
|
case syscall.EINVAL:
|
||||||
// Probably not a mountpoint, use bind-mount
|
// 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 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:
|
case syscall.EBUSY:
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
continue
|
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)
|
return fmt.Errorf("unable to bind-mount /dev/null over /proc/kcore: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,6 @@ import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/dotcloud/docker/pkg/mount"
|
|
||||||
"github.com/dotcloud/docker/pkg/system"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -14,6 +12,9 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/docker/libcontainer/system"
|
||||||
|
"github.com/dotcloud/docker/pkg/mount"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -153,16 +154,16 @@ func Getfilecon(path string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Setfscreatecon(scon 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) {
|
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.
|
// Return the SELinux label of the current process thread.
|
||||||
func Getcon() (string, error) {
|
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) {
|
func Getpidcon(pid int) (string, error) {
|
||||||
|
@ -192,7 +193,7 @@ func writeCon(name string, val string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Setexeccon(scon 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 {
|
func (c SELinuxContext) Get() string {
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
// +build linux,cgo
|
||||||
|
|
||||||
|
package system
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <unistd.h>
|
||||||
|
int get_hz(void) { return sysconf(_SC_CLK_TCK); }
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
func GetClockTicks() int {
|
||||||
|
return int(C.get_hz())
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче