package main import ( "crypto/md5" "fmt" "log" "os" "syscall" "github.com/codegangsta/cli" "github.com/docker/libcontainer" "github.com/docker/libcontainer/configs" ) var ( dataPath = os.Getenv("data_path") console = os.Getenv("console") rawPipeFd = os.Getenv("pipe") ) var execCommand = cli.Command{ Name: "exec", Usage: "execute a new command inside a container", Action: execAction, Flags: []cli.Flag{ cli.BoolFlag{Name: "list", Usage: "list all registered exec functions"}, cli.StringFlag{Name: "func", Value: "exec", Usage: "function name to exec inside a container"}, }, } func getContainer(context *cli.Context) (libcontainer.Container, error) { factory, err := libcontainer.New(context.GlobalString("root"), []string{os.Args[0], "init", "--fd", "3", "--"}) if err != nil { log.Fatal(err) } id := fmt.Sprintf("%x", md5.Sum([]byte(dataPath))) container, err := factory.Load(id) if err != nil && !os.IsNotExist(err) { var config *configs.Config config, err = loadConfig() if err != nil { log.Fatal(err) } container, err = factory.Create(id, config) } return container, err } func execAction(context *cli.Context) { var exitCode int process := &libcontainer.ProcessConfig{ Args: context.Args(), Env: context.StringSlice("env"), Stdin: os.Stdin, Stdout: os.Stdout, Stderr: os.Stderr, } container, err := getContainer(context) if err != nil { log.Fatal(err) } pid, err := container.StartProcess(process) if err != nil { log.Fatalf("failed to exec: %s", err) } p, err := os.FindProcess(pid) if err != nil { log.Fatalf("Unable to find the %d process: %s", pid, err) } ps, err := p.Wait() if err != nil { log.Fatalf("Unable to wait the %d process: %s", pid, err) } container.Destroy() status := ps.Sys().(syscall.WaitStatus) if status.Exited() { exitCode = status.ExitStatus() } else if status.Signaled() { exitCode = -int(status.Signal()) } else { log.Fatalf("Unexpected status") } os.Exit(exitCode) }