Handle non-tty mode

Docker-DCO-1.1-Signed-off-by: Guillaume J. Charmes <guillaume.charmes@docker.com> (github: creack)
This commit is contained in:
Guillaume J. Charmes 2014-02-20 18:05:40 -08:00 committed by Michael Crosby
parent 41696722fa
commit 97738ffed3
4 changed files with 70 additions and 30 deletions

View file

@ -16,10 +16,21 @@ import (
"syscall" "syscall"
) )
func execCommand(container *libcontainer.Container, args []string) (int, error) { func execCommand(container *libcontainer.Container, tty bool, args []string) (int, error) {
master, console, err := createMasterAndConsole() var (
if err != nil { master *os.File
return -1, err console string
err error
inPipe io.WriteCloser
outPipe, errPipe io.ReadCloser
)
if tty {
master, console, err = createMasterAndConsole()
if err != nil {
return -1, err
}
} }
// 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
@ -32,6 +43,21 @@ func execCommand(container *libcontainer.Container, args []string) (int, error)
command := createCommand(container, console, r.Fd(), args) command := createCommand(container, console, r.Fd(), args)
if !tty {
inPipe, err = command.StdinPipe()
if err != nil {
return -1, err
}
outPipe, err = command.StdoutPipe()
if err != nil {
return -1, err
}
errPipe, err = command.StderrPipe()
if err != nil {
return -1, err
}
}
if err := command.Start(); err != nil { if err := command.Start(); err != nil {
return -1, err return -1, err
} }
@ -63,15 +89,20 @@ func execCommand(container *libcontainer.Container, args []string) (int, error)
w.Close() w.Close()
r.Close() r.Close()
go io.Copy(os.Stdout, master) if tty {
go io.Copy(master, os.Stdin) go io.Copy(os.Stdout, master)
go io.Copy(master, os.Stdin)
state, err := setupWindow(master) state, err := setupWindow(master)
if err != nil { if err != nil {
command.Process.Kill() command.Process.Kill()
return -1, err return -1, err
}
defer term.RestoreTerminal(os.Stdin.Fd(), state)
} else {
go io.Copy(inPipe, os.Stdin)
go io.Copy(os.Stdout, outPipe)
go io.Copy(os.Stderr, errPipe)
} }
defer term.RestoreTerminal(os.Stdin.Fd(), state)
if err := command.Wait(); err != nil { if err := command.Wait(); err != nil {
if _, ok := err.(*exec.ExitError); !ok { if _, ok := err.(*exec.ExitError); !ok {

View file

@ -27,23 +27,27 @@ func initCommand(container *libcontainer.Container, console string, pipe io.Read
return err return err
} }
// close pipes so that we can replace it with the pty if console != "" {
os.Stdin.Close() // close pipes so that we can replace it with the pty
os.Stdout.Close() os.Stdin.Close()
os.Stderr.Close() os.Stdout.Close()
os.Stderr.Close()
slave, err := openTerminal(console, syscall.O_RDWR)
if err != nil {
return fmt.Errorf("open terminal %s", err)
}
if err := dupSlave(slave); err != nil {
return fmt.Errorf("dup2 slave %s", err)
}
}
slave, err := openTerminal(console, syscall.O_RDWR)
if err != nil {
return fmt.Errorf("open terminal %s", err)
}
if err := dupSlave(slave); err != nil {
return fmt.Errorf("dup2 slave %s", err)
}
if _, err := system.Setsid(); err != nil { if _, err := system.Setsid(); err != nil {
return fmt.Errorf("setsid %s", err) return fmt.Errorf("setsid %s", err)
} }
if err := system.Setctty(); err != nil { if console != "" {
return fmt.Errorf("setctty %s", err) if err := system.Setctty(); err != nil {
return fmt.Errorf("setctty %s", err)
}
} }
if err := system.ParentDeathSignal(); err != nil { if err := system.ParentDeathSignal(); err != nil {
return fmt.Errorf("parent deth signal %s", err) return fmt.Errorf("parent deth signal %s", err)

View file

@ -17,8 +17,11 @@ var (
) )
func main() { func main() {
console := flag.String("console", "", "Console (pty slave) name") var (
pipeFd := flag.Int("pipe", 0, "sync pipe fd") console = flag.String("console", "", "Console (pty slave) name")
tty = flag.Bool("tty", false, "Create a tty")
pipeFd = flag.Int("pipe", 0, "sync pipe fd")
)
flag.Parse() flag.Parse()
container, err := loadContainer() container, err := loadContainer()
@ -41,7 +44,7 @@ func main() {
if nspid > 0 { if nspid > 0 {
exitCode, err = execinCommand(container, nspid, flag.Args()[1:]) exitCode, err = execinCommand(container, nspid, flag.Args()[1:])
} else { } else {
exitCode, err = execCommand(container, flag.Args()[1:]) exitCode, err = execCommand(container, *tty, flag.Args()[1:])
} }
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)

View file

@ -40,8 +40,10 @@ func setupNewMountNamespace(rootfs, console string, readonly bool) error {
if err := setupDev(rootfs); err != nil { if err := setupDev(rootfs); err != nil {
return err return err
} }
if err := setupPtmx(rootfs, console); err != nil { if console != "" {
return err if err := setupPtmx(rootfs, console); err != nil {
return err
}
} }
if err := system.Chdir(rootfs); err != nil { if err := system.Chdir(rootfs); err != nil {
return fmt.Errorf("chdir into %s %s", rootfs, err) return fmt.Errorf("chdir into %s %s", rootfs, err)