summaryrefslogtreecommitdiff
path: root/runtime/execdriver/termconsole.go
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/execdriver/termconsole.go')
-rw-r--r--runtime/execdriver/termconsole.go126
1 files changed, 126 insertions, 0 deletions
diff --git a/runtime/execdriver/termconsole.go b/runtime/execdriver/termconsole.go
new file mode 100644
index 0000000000..af6b88d3d1
--- /dev/null
+++ b/runtime/execdriver/termconsole.go
@@ -0,0 +1,126 @@
+package execdriver
+
+import (
+ "github.com/dotcloud/docker/pkg/term"
+ "github.com/kr/pty"
+ "io"
+ "os"
+ "os/exec"
+)
+
+func SetTerminal(command *Command, pipes *Pipes) error {
+ var (
+ term Terminal
+ err error
+ )
+ if command.Tty {
+ term, err = NewTtyConsole(command, pipes)
+ } else {
+ term, err = NewStdConsole(command, pipes)
+ }
+ if err != nil {
+ return err
+ }
+ command.Terminal = term
+ return nil
+}
+
+type TtyConsole struct {
+ MasterPty *os.File
+ SlavePty *os.File
+}
+
+func NewTtyConsole(command *Command, pipes *Pipes) (*TtyConsole, error) {
+ ptyMaster, ptySlave, err := pty.Open()
+ if err != nil {
+ return nil, err
+ }
+ tty := &TtyConsole{
+ MasterPty: ptyMaster,
+ SlavePty: ptySlave,
+ }
+ if err := tty.AttachPipes(&command.Cmd, pipes); err != nil {
+ tty.Close()
+ return nil, err
+ }
+ command.Console = tty.SlavePty.Name()
+ return tty, nil
+}
+
+func (t *TtyConsole) Master() *os.File {
+ return t.MasterPty
+}
+
+func (t *TtyConsole) Resize(h, w int) error {
+ return term.SetWinsize(t.MasterPty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
+}
+
+func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *Pipes) error {
+ command.Stdout = t.SlavePty
+ command.Stderr = t.SlavePty
+
+ go func() {
+ if wb, ok := pipes.Stdout.(interface {
+ CloseWriters() error
+ }); ok {
+ defer wb.CloseWriters()
+ }
+ io.Copy(pipes.Stdout, t.MasterPty)
+ }()
+
+ if pipes.Stdin != nil {
+ command.Stdin = t.SlavePty
+ command.SysProcAttr.Setctty = true
+
+ go func() {
+ defer pipes.Stdin.Close()
+ io.Copy(t.MasterPty, pipes.Stdin)
+ }()
+ }
+ return nil
+}
+
+func (t *TtyConsole) Close() error {
+ t.SlavePty.Close()
+ return t.MasterPty.Close()
+}
+
+type StdConsole struct {
+}
+
+func NewStdConsole(command *Command, pipes *Pipes) (*StdConsole, error) {
+ std := &StdConsole{}
+
+ if err := std.AttachPipes(&command.Cmd, pipes); err != nil {
+ return nil, err
+ }
+ return std, nil
+}
+
+func (s *StdConsole) AttachPipes(command *exec.Cmd, pipes *Pipes) error {
+ command.Stdout = pipes.Stdout
+ command.Stderr = pipes.Stderr
+
+ if pipes.Stdin != nil {
+ stdin, err := command.StdinPipe()
+ 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
+}