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"
)
func execCommand(container *libcontainer.Container, args []string) (int, error) {
master, console, err := createMasterAndConsole()
if err != nil {
return -1, err
func execCommand(container *libcontainer.Container, tty bool, args []string) (int, error) {
var (
master *os.File
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
@ -32,6 +43,21 @@ func execCommand(container *libcontainer.Container, args []string) (int, error)
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 {
return -1, err
}
@ -63,15 +89,20 @@ func execCommand(container *libcontainer.Container, args []string) (int, error)
w.Close()
r.Close()
go io.Copy(os.Stdout, master)
go io.Copy(master, os.Stdin)
state, err := setupWindow(master)
if err != nil {
command.Process.Kill()
return -1, err
if tty {
go io.Copy(os.Stdout, master)
go io.Copy(master, os.Stdin)
state, err := setupWindow(master)
if err != nil {
command.Process.Kill()
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 _, ok := err.(*exec.ExitError); !ok {

View file

@ -27,23 +27,27 @@ func initCommand(container *libcontainer.Container, console string, pipe io.Read
return err
}
// close pipes so that we can replace it with the pty
os.Stdin.Close()
os.Stdout.Close()
os.Stderr.Close()
if console != "" {
// close pipes so that we can replace it with the pty
os.Stdin.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 {
return fmt.Errorf("setsid %s", err)
}
if err := system.Setctty(); err != nil {
return fmt.Errorf("setctty %s", err)
if console != "" {
if err := system.Setctty(); err != nil {
return fmt.Errorf("setctty %s", err)
}
}
if err := system.ParentDeathSignal(); err != nil {
return fmt.Errorf("parent deth signal %s", err)

View file

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

View file

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