Skip to content

Instantly share code, notes, and snippets.

@crosbymichael
Created February 6, 2014 19:44
Show Gist options
  • Select an option

  • Save crosbymichael/8851238 to your computer and use it in GitHub Desktop.

Select an option

Save crosbymichael/8851238 to your computer and use it in GitHub Desktop.
package main
import (
"flag"
"fmt"
"github.com/docker/libcontainer"
"os"
"path/filepath"
"syscall"
)
const (
CLONE_FS = 0x00000200
CLONE_FILES = 0x00000400
CLONE_NEWNS = 0x00020000 // mount
CLONE_NEWUTS = 0x04000000 // utsname
CLONE_NEWIPC = 0x08000000 // ipc
CLONE_NEWUSER = 0x10000000 // user
CLONE_NEWPID = 0x20000000 // pid
CLONE_NEWNET = 0x40000000 // network
CLONE_IO = 0x80000000
CLONE_VFORK = 0x00004000 // exec child right away
SIGCHLD = 0x14
SYS_SETNS = 308 // look here for different arch http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=7b21fddd087678a70ad64afc0f632e0f1071b092
STACK_SIZE = 1024 * 1024
)
func main() {
flag.Parse()
if flag.NArg() < 2 {
fmt.Fprintf(os.Stderr, "please provide [path] [cmd [args]]\n")
os.Exit(1)
}
abs, err := filepath.Abs(flag.Arg(0))
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
container := &libcontainer.Container{
RootFs: abs,
Command: flag.Arg(1),
Args: flag.Args()[2:],
Env: []string{
"HOME=/",
"PATH=$PATH:/bin:/usr/bin:/sbin:/usr/sbin",
"container=koye",
},
Network: &libcontainer.Network{
Host: true,
Disabled: false,
},
}
if err := Run(container); err != nil {
panic(err)
}
}
func Run(container *libcontainer.Container) error {
// need to make container.RootFs private so mounts dont propgate to host
// base namespaces without networking
if err := chdir(container.RootFs); err != nil {
return err
}
if err := chroot(container.RootFs); err != nil {
return err
}
flags := CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWNS
if !container.Network.Host {
flags |= CLONE_NEWNET
if !container.Network.Disabled {
if err := setupNetworking(container); err != nil {
return err
}
}
}
flags |= CLONE_VFORK
pid, err := clone(flags)
if err != nil {
return err
}
if pid != 0 {
// the pid here is our child's pid for the namespaces process on the host
exitcode, err := waitForChild(pid)
if err != nil {
return err
}
if err := cleanupOutsideNamespace(); err != nil {
return err
}
os.Exit(exitcode)
} else {
insideNamespace(container)
}
panic("unreachable")
}
func waitForChild(pid int) (int, error) {
child, err := os.FindProcess(pid)
if err != nil {
return -1, err
}
state, err := child.Wait()
if err != nil {
return -1, err
}
return state.Sys().(syscall.WaitStatus).ExitStatus(), nil
}
func cleanupOutsideNamespace() error {
// TODO: perform clean outside namespace
return nil
}
func insideNamespace(container *libcontainer.Container) {
if err := setupMounts(); err != nil {
panic(err)
}
if err := exec(container.Command, container.Args, container.Env); err != nil {
panic(err)
}
panic("unreachable")
}
func setupMounts() error {
if err := mount("proc", "proc", "proc", 0, ""); err != nil {
return err
}
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment