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:
parent
41696722fa
commit
97738ffed3
4 changed files with 70 additions and 30 deletions
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue