diff --git a/exec.go b/exec.go index 39dfd477..41ce6c91 100644 --- a/exec.go +++ b/exec.go @@ -43,6 +43,15 @@ var execCommand = cli.Command{ Name: "process,p", Usage: "path to the process.json", }, + 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) { if os.Geteuid() != 0 { @@ -61,7 +70,10 @@ func execProcess(context *cli.Context) (int, error) { if err != nil { return -1, err } - bundle := container.Config().Rootfs + var ( + detach = context.Bool("detach") + bundle = container.Config().Rootfs + ) rootuid, err := container.Config().HostUID() if err != nil { return -1, err @@ -71,15 +83,23 @@ func execProcess(context *cli.Context) (int, error) { return -1, err } process := newProcess(*p) - tty, err := newTty(p.Terminal, process, rootuid, context.String("console")) + tty, err := setupIO(process, rootuid, context.String("console"), p.Terminal, detach) if 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 != "" { + if err := createPidile(pidFile, process); err != nil { + return -1, err + } + } + if detach { + return 0, nil + } + handler := newSignalHandler(tty) + defer handler.Close() return handler.forward(process) } diff --git a/start.go b/start.go index 7ba4d589..69ef6142 100644 --- a/start.go +++ b/start.go @@ -132,38 +132,17 @@ func startContainer(context *cli.Context, spec *specs.LinuxSpec, rspec *specs.Li process.ExtraFiles = append(process.ExtraFiles, os.NewFile(uintptr(i), "")) } } - 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 - } + tty, err := setupIO(process, rootuid, context.String("console"), spec.Process.Terminal, detach) + if err != nil { + return -1, err } if err := container.Start(process); err != nil { return -1, err } if pidFile := context.String("pid-file"); pidFile != "" { - pid, err := process.Pid() - if err != nil { + if err := createPidile(pidFile, process); 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 @@ -209,3 +188,39 @@ func destroy(container libcontainer.Container) { logrus.Error(err) } } + +func setupIO(process *libcontainer.Process, rootuid int, console string, createTTY, detach bool) (*tty, error) { + // detach and createTty will not work unless a console path is passed + // so error out here before changing any terminal settings + if createTTY && detach && console == "" { + return nil, fmt.Errorf("cannot allocate tty if runc will detach") + } + if createTTY { + return createTty(process, rootuid, console) + } + if detach { + if err := dupStdio(process, rootuid); err != nil { + return nil, err + } + return nil, nil + } + return createStdioPipes(process, rootuid) +} + +func createPidile(path string, process *libcontainer.Process) error { + pid, err := process.Pid() + if err != nil { + return err + } + f, err := os.Create(path) + 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") + } + } + return nil +}