diff --git a/delete.go b/delete.go new file mode 100644 index 000000000..41b377855 --- /dev/null +++ b/delete.go @@ -0,0 +1,15 @@ +package main + +import "github.com/codegangsta/cli" + +var deleteCommand = cli.Command{ + Name: "delete", + Usage: "delete any resources held by the container often used with detached containers", + Action: func(context *cli.Context) { + container, err := getContainer(context) + if err != nil { + fatal(err) + } + destroy(container) + }, +} diff --git a/libcontainer/state_linux.go b/libcontainer/state_linux.go index fb71ef97d..9ffe15a43 100644 --- a/libcontainer/state_linux.go +++ b/libcontainer/state_linux.go @@ -219,5 +219,8 @@ func (n *createdState) transition(s containerState) error { } func (n *createdState) destroy() error { - return nil + if err := n.c.refreshState(); err != nil { + return err + } + return n.c.state.destroy() } diff --git a/main.go b/main.go index ba7d8928d..4142172b3 100644 --- a/main.go +++ b/main.go @@ -70,16 +70,18 @@ func main() { }, } app.Commands = []cli.Command{ - startCommand, checkpointCommand, + deleteCommand, eventsCommand, - restoreCommand, - killCommand, - specCommand, - pauseCommand, - resumeCommand, execCommand, + execCommand, + killCommand, listCommand, + pauseCommand, + restoreCommand, + resumeCommand, + specCommand, + startCommand, } app.Before = func(context *cli.Context) error { if context.GlobalBool("debug") { diff --git a/start.go b/start.go index 8f2d85845..7ba4d589a 100644 --- a/start.go +++ b/start.go @@ -7,6 +7,7 @@ import ( "os" "runtime" "strconv" + "syscall" "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" @@ -31,6 +32,15 @@ var startCommand = cli.Command{ Value: "", Usage: "specify the pty slave path for use with the container", }, + cli.BoolFlag{ + Name: "detach,d", + Usage: "detach from the container's process", + }, + cli.StringFlag{ + Name: "pid-file", + Value: "", + Usage: "specify the file to write the process id to", + }, }, Action: func(context *cli.Context) { bundle := context.String("bundle") @@ -107,10 +117,11 @@ func startContainer(context *cli.Context, spec *specs.LinuxSpec, rspec *specs.Li } // ensure that the container is always removed if we were the process // that created it. - defer destroy(container) - + detach := context.Bool("detach") + if !detach { + defer destroy(container) + } process := newProcess(spec.Process) - // Support on-demand socket activation by passing file descriptors into the container init process. if os.Getenv("LISTEN_FDS") != "" { listenFdsInt, err := strconv.Atoi(os.Getenv("LISTEN_FDS")) @@ -121,18 +132,63 @@ func startContainer(context *cli.Context, spec *specs.LinuxSpec, rspec *specs.Li process.ExtraFiles = append(process.ExtraFiles, os.NewFile(uintptr(i), "")) } } - tty, err := newTty(spec.Process.Terminal, process, rootuid, context.String("console")) - if err != nil { - return -1, err + var tty *tty + if spec.Process.Terminal { + if tty, err = createTty(process, rootuid, context.String("console")); err != nil { + return -1, err + } + } else if detach { + if err := dupStdio(process, rootuid); err != nil { + return -1, err + } + } else { + if tty, err = createStdioPipes(process, rootuid); err != nil { + return -1, err + } } - handler := newSignalHandler(tty) - defer handler.Close() if err := container.Start(process); err != nil { return -1, err } + if pidFile := context.String("pid-file"); pidFile != "" { + pid, err := process.Pid() + if err != nil { + return -1, err + } + f, err := os.Create(pidFile) + if err != nil { + logrus.WithField("pid", pid).Error("create pid file") + } else { + _, err = fmt.Fprintf(f, "%d", pid) + f.Close() + if err != nil { + logrus.WithField("error", err).Error("write pid file") + } + } + } + if detach { + return 0, nil + } + handler := newSignalHandler(tty) + defer handler.Close() return handler.forward(process) } +func dupStdio(process *libcontainer.Process, rootuid int) error { + process.Stdin = os.Stdin + process.Stdout = os.Stdout + process.Stderr = os.Stderr + for _, fd := range []uintptr{ + os.Stdin.Fd(), + os.Stdout.Fd(), + os.Stderr.Fd(), + } { + if err := syscall.Fchown(int(fd), rootuid, rootuid); err != nil { + return err + } + } + return nil +} + // If systemd is supporting sd_notify protocol, this function will add support // for sd_notify protocol from within the container. func setupSdNotify(spec *specs.LinuxSpec, rspec *specs.LinuxRuntimeSpec, notifySocket string) {