2014-02-24 15:28:45 -05:00
|
|
|
package execdriver
|
2014-02-21 15:32:14 -05:00
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/dotcloud/docker/pkg/term"
|
|
|
|
"github.com/kr/pty"
|
|
|
|
"io"
|
|
|
|
"os"
|
2014-02-22 04:21:26 -05:00
|
|
|
"os/exec"
|
2014-02-21 15:32:14 -05:00
|
|
|
)
|
|
|
|
|
2014-02-24 15:28:45 -05:00
|
|
|
func SetTerminal(command *Command, pipes *Pipes) error {
|
2014-02-21 15:32:14 -05:00
|
|
|
var (
|
2014-02-24 15:28:45 -05:00
|
|
|
term Terminal
|
2014-02-21 15:32:14 -05:00
|
|
|
err error
|
|
|
|
)
|
|
|
|
if command.Tty {
|
2014-02-21 15:42:37 -05:00
|
|
|
term, err = NewTtyConsole(command, pipes)
|
2014-02-21 15:32:14 -05:00
|
|
|
} else {
|
2014-02-21 15:42:37 -05:00
|
|
|
term, err = NewStdConsole(command, pipes)
|
2014-02-21 15:32:14 -05:00
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
command.Terminal = term
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type TtyConsole struct {
|
2014-02-22 04:21:26 -05:00
|
|
|
MasterPty *os.File
|
|
|
|
SlavePty *os.File
|
2014-02-21 15:32:14 -05:00
|
|
|
}
|
|
|
|
|
2014-02-24 15:28:45 -05:00
|
|
|
func NewTtyConsole(command *Command, pipes *Pipes) (*TtyConsole, error) {
|
2014-02-21 15:32:14 -05:00
|
|
|
ptyMaster, ptySlave, err := pty.Open()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
tty := &TtyConsole{
|
2014-02-22 04:21:26 -05:00
|
|
|
MasterPty: ptyMaster,
|
|
|
|
SlavePty: ptySlave,
|
2014-02-21 15:42:37 -05:00
|
|
|
}
|
2014-02-22 04:21:26 -05:00
|
|
|
if err := tty.AttachPipes(&command.Cmd, pipes); err != nil {
|
2014-02-21 15:42:37 -05:00
|
|
|
tty.Close()
|
|
|
|
return nil, err
|
2014-02-21 15:32:14 -05:00
|
|
|
}
|
2014-02-22 04:21:26 -05:00
|
|
|
command.Console = tty.SlavePty.Name()
|
2014-02-21 15:32:14 -05:00
|
|
|
return tty, nil
|
|
|
|
}
|
|
|
|
|
2014-02-21 16:27:15 -05:00
|
|
|
func (t *TtyConsole) Master() *os.File {
|
2014-02-22 04:21:26 -05:00
|
|
|
return t.MasterPty
|
2014-02-21 16:27:15 -05:00
|
|
|
}
|
|
|
|
|
2014-02-21 15:32:14 -05:00
|
|
|
func (t *TtyConsole) Resize(h, w int) error {
|
2014-02-22 04:21:26 -05:00
|
|
|
return term.SetWinsize(t.MasterPty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
|
2014-02-21 15:32:14 -05:00
|
|
|
}
|
|
|
|
|
2014-02-26 15:55:24 -05:00
|
|
|
func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *Pipes) error {
|
2014-02-22 04:21:26 -05:00
|
|
|
command.Stdout = t.SlavePty
|
|
|
|
command.Stderr = t.SlavePty
|
2014-02-21 15:32:14 -05:00
|
|
|
|
|
|
|
go func() {
|
2014-02-21 15:52:18 -05:00
|
|
|
if wb, ok := pipes.Stdout.(interface {
|
|
|
|
CloseWriters() error
|
|
|
|
}); ok {
|
|
|
|
defer wb.CloseWriters()
|
|
|
|
}
|
2014-02-22 04:21:26 -05:00
|
|
|
io.Copy(pipes.Stdout, t.MasterPty)
|
2014-02-21 15:32:14 -05:00
|
|
|
}()
|
|
|
|
|
|
|
|
if pipes.Stdin != nil {
|
2014-02-22 04:21:26 -05:00
|
|
|
command.Stdin = t.SlavePty
|
2014-02-21 15:42:37 -05:00
|
|
|
command.SysProcAttr.Setctty = true
|
2014-02-21 15:32:14 -05:00
|
|
|
|
|
|
|
go func() {
|
|
|
|
defer pipes.Stdin.Close()
|
2014-02-22 04:21:26 -05:00
|
|
|
io.Copy(t.MasterPty, pipes.Stdin)
|
2014-02-21 15:32:14 -05:00
|
|
|
}()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *TtyConsole) Close() error {
|
2014-02-22 04:21:26 -05:00
|
|
|
t.SlavePty.Close()
|
|
|
|
return t.MasterPty.Close()
|
2014-02-21 15:32:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
type StdConsole struct {
|
|
|
|
}
|
|
|
|
|
2014-02-24 15:28:45 -05:00
|
|
|
func NewStdConsole(command *Command, pipes *Pipes) (*StdConsole, error) {
|
2014-02-21 15:42:37 -05:00
|
|
|
std := &StdConsole{}
|
|
|
|
|
2014-02-22 04:21:26 -05:00
|
|
|
if err := std.AttachPipes(&command.Cmd, pipes); err != nil {
|
2014-02-21 15:42:37 -05:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return std, nil
|
2014-02-21 15:32:14 -05:00
|
|
|
}
|
|
|
|
|
2014-02-26 15:55:24 -05:00
|
|
|
func (s *StdConsole) AttachPipes(command *exec.Cmd, pipes *Pipes) error {
|
2014-02-21 15:42:37 -05:00
|
|
|
command.Stdout = pipes.Stdout
|
|
|
|
command.Stderr = pipes.Stderr
|
2014-02-21 15:32:14 -05:00
|
|
|
|
|
|
|
if pipes.Stdin != nil {
|
2014-02-21 15:42:37 -05:00
|
|
|
stdin, err := command.StdinPipe()
|
2014-02-21 15:32:14 -05:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
defer stdin.Close()
|
|
|
|
io.Copy(stdin, pipes.Stdin)
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *StdConsole) Resize(h, w int) error {
|
|
|
|
// we do not need to reside a non tty
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *StdConsole) Close() error {
|
|
|
|
// nothing to close here
|
|
|
|
return nil
|
|
|
|
}
|