Beispiel #1
1
func (container *Container) startPty() error {
	ptyMaster, ptySlave, err := pty.Open()
	if err != nil {
		return err
	}
	container.ptyMaster = ptyMaster
	container.cmd.Stdout = ptySlave
	container.cmd.Stderr = ptySlave

	// Copy the PTYs to our broadcasters
	go func() {
		defer container.stdout.CloseWriters()
		utils.Debugf("[startPty] Begin of stdout pipe")
		io.Copy(container.stdout, ptyMaster)
		utils.Debugf("[startPty] End of stdout pipe")
	}()

	// stdin
	if container.Config.OpenStdin {
		container.cmd.Stdin = ptySlave
		container.cmd.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true}
		go func() {
			defer container.stdin.Close()
			utils.Debugf("[startPty] Begin of stdin pipe")
			io.Copy(ptyMaster, container.stdin)
			utils.Debugf("[startPty] End of stdin pipe")
		}()
	}
	if err := container.cmd.Start(); err != nil {
		return err
	}
	ptySlave.Close()
	return nil
}
// #5979
func (s *DockerSuite) TestEventsRedirectStdout(c *check.C) {
	since := daemonTime(c).Unix()
	dockerCmd(c, "run", "busybox", "true")

	file, err := ioutil.TempFile("", "")
	c.Assert(err, checker.IsNil, check.Commentf("could not create temp file"))
	defer os.Remove(file.Name())

	command := fmt.Sprintf("%s events --since=%d --until=%d > %s", dockerBinary, since, daemonTime(c).Unix(), file.Name())
	_, tty, err := pty.Open()
	c.Assert(err, checker.IsNil, check.Commentf("Could not open pty"))
	cmd := exec.Command("sh", "-c", command)
	cmd.Stdin = tty
	cmd.Stdout = tty
	cmd.Stderr = tty
	c.Assert(cmd.Run(), checker.IsNil, check.Commentf("run err for command %q", command))

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		for _, ch := range scanner.Text() {
			c.Assert(unicode.IsControl(ch), checker.False, check.Commentf("found control character %v", []byte(string(ch))))
		}
	}
	c.Assert(scanner.Err(), checker.IsNil, check.Commentf("Scan err for command %q", command))

}
Beispiel #3
0
func (container *Container) startPty() error {
	stdoutMaster, stdoutSlave, err := pty.Open()
	if err != nil {
		return err
	}
	container.ptyStdoutMaster = stdoutMaster
	container.cmd.Stdout = stdoutSlave

	stderrMaster, stderrSlave, err := pty.Open()
	if err != nil {
		return err
	}
	container.ptyStderrMaster = stderrMaster
	container.cmd.Stderr = stderrSlave

	// Copy the PTYs to our broadcasters
	go func() {
		defer container.stdout.CloseWriters()
		Debugf("[startPty] Begin of stdout pipe")
		io.Copy(container.stdout, stdoutMaster)
		Debugf("[startPty] End of stdout pipe")
	}()

	go func() {
		defer container.stderr.CloseWriters()
		Debugf("[startPty] Begin of stderr pipe")
		io.Copy(container.stderr, stderrMaster)
		Debugf("[startPty] End of stderr pipe")
	}()

	// stdin
	var stdinSlave io.ReadCloser
	if container.Config.OpenStdin {
		var stdinMaster io.WriteCloser
		stdinMaster, stdinSlave, err = pty.Open()
		if err != nil {
			return err
		}
		container.ptyStdinMaster = stdinMaster
		container.cmd.Stdin = stdinSlave
		// FIXME: The following appears to be broken.
		// "cannot set terminal process group (-1): Inappropriate ioctl for device"
		// container.cmd.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true}
		go func() {
			defer container.stdin.Close()
			Debugf("[startPty] Begin of stdin pipe")
			io.Copy(stdinMaster, container.stdin)
			Debugf("[startPty] End of stdin pipe")
		}()
	}
	if err := container.cmd.Start(); err != nil {
		return err
	}
	stdoutSlave.Close()
	stderrSlave.Close()
	if stdinSlave != nil {
		stdinSlave.Close()
	}
	return nil
}
Beispiel #4
0
func createJob(client *beam.Client) *beam.Job {
	job, err := client.NewJob("tty")
	if err != nil {
		panic(err)
	}

	master, slave, err := pty.Open()
	if err != nil {
		panic(err)
	}

	_, err = term.SetRawTerminal(master.Fd())
	if err != nil {
		panic(err)
	}

	go job.WriteTo(slave, "stdout")
	go job.WriteTo(slave, "stderr")
	go job.ReadFrom(slave, "stdin")

	go io.Copy(os.Stdout, master)
	go io.Copy(os.Stderr, master)
	go io.Copy(master, os.Stdin)

	return job
}
Beispiel #5
0
func worker() {
	worker := beam.NewWorker(&beam.NetTransport{"tcp", ":6379"}, "/jobs")
	worker.RegisterJob("tty", func(name string, args []string, env map[string]string, streams beam.Streamer, db beam.DB) error {
		p := exec.Command("bash")

		master, slave, err := pty.Open()
		if err != nil {
			return err
		}
		if slave == nil {
			return fmt.Errorf("tty is nil")
		}

		term.SetWinsize(master.Fd(), winsize)

		p.Stdout = slave
		p.Stderr = slave
		p.Stdin = slave
		p.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true}

		go streams.ReadFrom(master, "stdout")
		go streams.ReadFrom(master, "stderr")
		go streams.WriteTo(master, "stdin")

		return p.Run()
	})
	worker.Work()
}
Beispiel #6
0
func (s *GitDeploySuite) TestDevStdout(t *c.C) {
	r := s.newGitRepo(t, "empty-release")
	t.Assert(r.flynn("create"), Succeeds)
	t.Assert(r.flynn("env", "set", "BUILDPACK_URL=https://github.com/kr/heroku-buildpack-inline"), Succeeds)
	t.Assert(r.git("push", "flynn", "master"), Succeeds)

	// check slug jobs can write to /dev/stdout and /dev/stderr
	for _, dev := range []string{"/dev/stdout", "/dev/stderr"} {
		// check without a TTY
		echoFoo := fmt.Sprintf("echo foo > %s", dev)
		t.Assert(r.flynn("run", "bash", "-c", echoFoo), SuccessfulOutputContains, "foo")

		// check with a TTY
		cmd := flynnCmd(r.dir, "run", "bash", "-c", echoFoo)
		master, slave, err := pty.Open()
		t.Assert(err, c.IsNil)
		defer master.Close()
		defer slave.Close()
		t.Assert(term.SetWinsize(slave.Fd(), &term.Winsize{Height: 24, Width: 80}), c.IsNil)
		cmd.Stdin = slave
		cmd.Stdout = slave
		cmd.Stderr = slave
		t.Assert(cmd.Run(), c.IsNil)
		out := make([]byte, 3)
		_, err = io.ReadFull(master, out)
		t.Assert(err, c.IsNil)
		t.Assert(string(out), c.Equals, "foo")
	}
}
Beispiel #7
0
func (pipe *Pipe) runPtyCmd(cmd *exec.Cmd) error {
	py, tty, err := pty.Open()
	if err != nil {
		return err
	}
	defer tty.Close()
	env := os.Environ()
	env = append(env, "TERM=xterm")
	cmd.Env = env
	cmd.Stdout = tty
	cmd.Stdin = tty
	cmd.Stderr = tty
	cmd.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true}
	ws := &Winsize{
		Width:  uint16(pipe.opts.Width),
		Height: uint16(pipe.opts.Height),
	}
	_, _, syserr := syscall.Syscall(syscall.SYS_IOCTL, py.Fd(), uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(ws)))
	if syserr != 0 {
		return syserr
	}
	pCmd := pipedCmd{
		pipe:   pipe,
		cmd:    cmd,
		stdin:  py,
		stdout: py,
		stderr: nil,
	}
	return pCmd.run()
}
// TestRunDetach checks attaching and detaching with the escape sequence specified via flags.
func (s *DockerSuite) TestRunAttachDetachFromFlag(c *check.C) {
	name := "attach-detach"
	keyCtrlA := []byte{1}
	keyA := []byte{97}

	dockerCmd(c, "run", "--name", name, "-itd", "busybox", "cat")

	cmd := exec.Command(dockerBinary, "attach", "--detach-keys='ctrl-a,a'", name)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		c.Fatal(err)
	}
	cpty, tty, err := pty.Open()
	if err != nil {
		c.Fatal(err)
	}
	defer cpty.Close()
	cmd.Stdin = tty
	if err := cmd.Start(); err != nil {
		c.Fatal(err)
	}
	c.Assert(waitRun(name), check.IsNil)

	if _, err := cpty.Write([]byte("hello\n")); err != nil {
		c.Fatal(err)
	}

	out, err := bufio.NewReader(stdout).ReadString('\n')
	if err != nil {
		c.Fatal(err)
	}
	if strings.TrimSpace(out) != "hello" {
		c.Fatalf("expected 'hello', got %q", out)
	}

	// escape sequence
	if _, err := cpty.Write(keyCtrlA); err != nil {
		c.Fatal(err)
	}
	time.Sleep(100 * time.Millisecond)
	if _, err := cpty.Write(keyA); err != nil {
		c.Fatal(err)
	}

	ch := make(chan struct{})
	go func() {
		cmd.Wait()
		ch <- struct{}{}
	}()

	select {
	case <-ch:
	case <-time.After(10 * time.Second):
		c.Fatal("timed out waiting for container to exit")
	}

	running, err := inspectField(name, "State.Running")
	c.Assert(err, checker.IsNil)
	c.Assert(running, checker.Equals, "true", check.Commentf("expected container to still be running"))
}
Beispiel #9
0
func createTtyPty(windowColumns int, windowRows int) (stdinR, stdinW, stdoutR, stdoutW, stderrR, stderrW *os.File, err error) {
	// stderr will not be assigned in the case of a tty, so ensure it will return EOF on read
	stderrR, err = os.Open("/dev/null")
	if err != nil {
		return nil, nil, nil, nil, nil, nil, err
	}

	pty, tty, err := pty.Open()
	if err != nil {
		return nil, nil, nil, nil, nil, nil, err
	}

	// do NOT assign stderrR to pty; the receiving end should only receive one
	// pty output stream, as they're both the same fd

	stdinW = pty
	stdoutR = pty

	stdinR = tty
	stdoutW = tty
	stderrW = tty

	setWinSize(stdinW, windowColumns, windowRows)

	return
}
// #6509
func (s *DockerSuite) TestRunRedirectStdout(c *check.C) {
	checkRedirect := func(command string) {
		_, tty, err := pty.Open()
		c.Assert(err, checker.IsNil, check.Commentf("Could not open pty"))
		cmd := exec.Command("sh", "-c", command)
		cmd.Stdin = tty
		cmd.Stdout = tty
		cmd.Stderr = tty
		c.Assert(cmd.Start(), checker.IsNil)
		ch := make(chan error)
		go func() {
			ch <- cmd.Wait()
			close(ch)
		}()

		select {
		case <-time.After(10 * time.Second):
			c.Fatal("command timeout")
		case err := <-ch:
			c.Assert(err, checker.IsNil, check.Commentf("wait err"))
		}
	}

	checkRedirect(dockerBinary + " run -i busybox cat /etc/passwd | grep -q root")
	checkRedirect(dockerBinary + " run busybox cat /etc/passwd | grep -q root")
}
func (s *DockerSuite) TestUpdateNotAffectMonitorRestartPolicy(c *check.C) {
	testRequires(c, DaemonIsLinux, cpuShare)

	out, _ := dockerCmd(c, "run", "-tid", "--restart=always", "busybox", "sh")
	id := strings.TrimSpace(string(out))
	dockerCmd(c, "update", "--cpu-shares", "512", id)

	cpty, tty, err := pty.Open()
	c.Assert(err, checker.IsNil)
	defer cpty.Close()

	cmd := exec.Command(dockerBinary, "attach", id)
	cmd.Stdin = tty

	c.Assert(cmd.Start(), checker.IsNil)
	defer cmd.Process.Kill()

	_, err = cpty.Write([]byte("exit\n"))
	c.Assert(err, checker.IsNil)

	c.Assert(cmd.Wait(), checker.IsNil)

	// container should restart again and keep running
	err = waitInspect(id, "{{.RestartCount}}", "1", 30*time.Second)
	c.Assert(err, checker.IsNil)
	c.Assert(waitRun(id), checker.IsNil)
}
Beispiel #12
0
func TestIsTerminal(t *testing.T) {
	mpty, mtty, err := pty.Open()
	if err != nil {
		t.Fatal(err)
	}
	defer mtty.Close()
	defer mpty.Close()

	if !ttyutils.IsTerminal(mtty.Fd()) {
		t.Error("tty should be reported as a terminal")
	}
	if !ttyutils.IsTerminal(mpty.Fd()) {
		t.Error("pty should be reported as a terminal")
	}

	null, err := os.Open(os.DevNull)
	if err != nil {
		t.Fatal(err)
	}
	defer null.Close()

	if ttyutils.IsTerminal(null.Fd()) {
		t.Error("/dev/null should not be reported as a terminal")
	}
}
Beispiel #13
0
func record() {
	C.ttySave()
	defer C.ttyRestore()
	C.ttyRaw()

	master, slave, err := pty.Open()
	if err != nil {
		log.Fatalln("open:", err)
	}
	C.ttyFixWinsz(C.int(slave.Fd()))
	script, err := os.OpenFile("ttyrecord", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		log.Fatalln(err)
	}

	sh := os.Getenv("SHELL")
	if sh == "" {
		sh = "/bin/sh"
	}
	attr := &syscall.SysProcAttr{
		Setsid:  true,
		Setctty: true,
		Ctty:    int(slave.Fd()),
	}
	shell := &exec.Cmd{
		Path:        sh,
		SysProcAttr: attr,
		Stdin:       slave,
		Stdout:      slave,
		Stderr:      slave,
	}
	go io.Copy(master, os.Stdin)
	go io.Copy(io.MultiWriter(newGobWriter(script), os.Stdout), master)
	shell.Run()
}
Beispiel #14
0
func (container *Container) setupPty() error {
	ptyMaster, ptySlave, err := pty.Open()
	if err != nil {
		return err
	}
	container.ptyMaster = ptyMaster
	container.command.Stdout = ptySlave
	container.command.Stderr = ptySlave

	// Copy the PTYs to our broadcasters
	go func() {
		defer container.stdout.CloseWriters()
		utils.Debugf("startPty: begin of stdout pipe")
		io.Copy(container.stdout, ptyMaster)
		utils.Debugf("startPty: end of stdout pipe")
	}()

	// stdin
	if container.Config.OpenStdin {
		container.command.Stdin = ptySlave
		container.command.SysProcAttr.Setctty = true
		go func() {
			defer container.stdin.Close()
			utils.Debugf("startPty: begin of stdin pipe")
			io.Copy(ptyMaster, container.stdin)
			utils.Debugf("startPty: end of stdin pipe")
		}()
	}
	return nil
}
Beispiel #15
0
func NewTtyConsole(processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes) (*TtyConsole, error) {
	// lxc is special in that we cannot create the master outside of the container without
	// opening the slave because we have nothing to provide to the cmd.  We have to open both then do
	// the crazy setup on command right now instead of passing the console path to lxc and telling it
	// to open up that console.  we save a couple of openfiles in the native driver because we can do
	// this.
	ptyMaster, ptySlave, err := pty.Open()
	if err != nil {
		return nil, err
	}

	tty := &TtyConsole{
		MasterPty: ptyMaster,
		SlavePty:  ptySlave,
	}

	if err := tty.AttachPipes(&processConfig.Cmd, pipes); err != nil {
		tty.Close()
		return nil, err
	}

	processConfig.Console = tty.SlavePty.Name()

	return tty, nil
}
Beispiel #16
0
// HandleChannel handles one SSH channel
func (c *Client) HandleChannel(newChannel ssh.NewChannel) error {
	if newChannel.ChannelType() != "session" {
		log.Debugf("Unknown channel type: %s", newChannel.ChannelType())
		newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
		return nil
	}

	channel, requests, err := newChannel.Accept()
	if err != nil {
		log.Errorf("newChannel.Accept failed: %v", err)
		return err
	}
	c.ChannelIdx++
	log.Debugf("HandleChannel.channel (client=%d channel=%d)", c.Idx, c.ChannelIdx)

	log.Debug("Creating pty...")
	c.Pty, c.Tty, err = pty.Open()
	if err != nil {
		log.Errorf("pty.Open failed: %v", err)
		return nil
	}

	c.HandleChannelRequests(channel, requests)

	return nil
}
// TestRunDetach checks attaching and detaching with the escape sequence specified via flags.
func (s *DockerSuite) TestRunAttachDetachFromInvalidFlag(c *check.C) {
	name := "attach-detach"
	dockerCmd(c, "run", "--name", name, "-itd", "busybox", "top")
	c.Assert(waitRun(name), check.IsNil)

	// specify an invalid detach key, container will ignore it and use default
	cmd := exec.Command(dockerBinary, "attach", "--detach-keys='ctrl-A,a'", name)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		c.Fatal(err)
	}
	cpty, tty, err := pty.Open()
	if err != nil {
		c.Fatal(err)
	}
	defer cpty.Close()
	cmd.Stdin = tty
	if err := cmd.Start(); err != nil {
		c.Fatal(err)
	}

	bufReader := bufio.NewReader(stdout)
	out, err := bufReader.ReadString('\n')
	if err != nil {
		c.Fatal(err)
	}
	// it should print a warning to indicate the detach key flag is invalid
	errStr := "Invalid escape keys (ctrl-A,a) provided"
	c.Assert(strings.TrimSpace(out), checker.Equals, errStr)
}
Beispiel #18
0
func handleConnection(c net.Conn) {
	defer c.Close()

	// Start the command
	cmd := exec.Command(flagCommand)

	// Create PTY
	pty, tty, err := pty.Open()
	if err != nil {
		log.Printf("error: could not open PTY: %s", err)
		return
	}
	defer tty.Close()
	defer pty.Close()

	// Put the TTY into raw mode
	_, err = terminal.MakeRaw(int(tty.Fd()))
	if err != nil {
		log.Printf("warn: could not make TTY raw: %s", err)
	}

	// Hook everything up
	cmd.Stdout = tty
	cmd.Stdin = tty
	cmd.Stderr = tty
	if cmd.SysProcAttr == nil {
		cmd.SysProcAttr = &syscall.SysProcAttr{}
	}

	cmd.SysProcAttr.Setctty = true
	cmd.SysProcAttr.Setsid = true

	// Start command
	err = cmd.Start()
	if err != nil {
		log.Printf("error: could not start command: %s", err)
		return
	}

	errs := make(chan error, 3)

	go func() {
		_, err := io.Copy(c, pty)
		errs <- err
	}()
	go func() {
		_, err := io.Copy(pty, c)
		errs <- err
	}()
	go func() {
		errs <- cmd.Wait()
	}()

	// Wait for a single error, then shut everything down. Since returning from
	// this function closes the connection, we just read a single error and
	// then continue.
	<-errs
	log.Printf("info: connection from %s finished", c.RemoteAddr())
}
Beispiel #19
0
// NewTty creates a pseudo-TTY for a command and modifies it appropriately so
// the command thinks it's a real terminal
func NewTty(cmd *exec.Cmd) *Tty {
	tty := &Tty{}
	tty.cmd = cmd
	// Assign pty/tty so git thinks it's a real terminal
	tty.outpty, tty.outtty, _ = pty.Open()
	cmd.Stdin = tty.outtty
	cmd.Stdout = tty.outtty
	tty.errpty, tty.errtty, _ = pty.Open()
	cmd.Stderr = tty.errtty
	if cmd.SysProcAttr == nil {
		cmd.SysProcAttr = &syscall.SysProcAttr{}
	}
	cmd.SysProcAttr.Setctty = true
	cmd.SysProcAttr.Setsid = true

	return tty
}
Beispiel #20
0
// TestRunDetach checks attaching and detaching with the escape sequence.
func TestRunDetach(t *testing.T) {
	stdout, stdoutPipe := io.Pipe()
	cpty, tty, err := pty.Open()
	if err != nil {
		t.Fatal(err)
	}

	key, err := libtrust.GenerateECP256PrivateKey()
	if err != nil {
		t.Fatal(err)
	}

	cli := client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, key, testDaemonProto, testDaemonAddr, nil)
	defer cleanup(globalEngine, t)

	ch := make(chan struct{})
	go func() {
		defer close(ch)
		cli.CmdRun("-i", "-t", unitTestImageID, "cat")
	}()

	container := waitContainerStart(t, 10*time.Second)

	state := setRaw(t, container)
	defer unsetRaw(t, container, state)

	setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
		if err := assertPipe("hello\n", "hello", stdout, cpty, 150); err != nil {
			t.Fatal(err)
		}
	})

	setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
		cpty.Write([]byte{16})
		time.Sleep(100 * time.Millisecond)
		cpty.Write([]byte{17})
	})

	// wait for CmdRun to return
	setTimeout(t, "Waiting for CmdRun timed out", 15*time.Second, func() {
		<-ch
	})
	closeWrap(cpty, stdout, stdoutPipe)

	time.Sleep(500 * time.Millisecond)
	if !container.IsRunning() {
		t.Fatal("The detached container should be still running")
	}

	setTimeout(t, "Waiting for container to die timed out", 20*time.Second, func() {
		container.Kill()
	})
}
// save a repo and try to load it using stdout
func (s *DockerSuite) TestSaveAndLoadRepoStdout(c *check.C) {
	name := "test-save-and-load-repo-stdout"
	dockerCmd(c, "run", "--name", name, "busybox", "true")

	repoName := "foobar-save-load-test"
	before, _ := dockerCmd(c, "commit", name, repoName)
	before = strings.TrimRight(before, "\n")

	tmpFile, err := ioutil.TempFile("", "foobar-save-load-test.tar")
	c.Assert(err, check.IsNil)
	defer os.Remove(tmpFile.Name())

	saveCmd := exec.Command(dockerBinary, "save", repoName)
	saveCmd.Stdout = tmpFile

	_, err = runCommand(saveCmd)
	c.Assert(err, check.IsNil)

	tmpFile, err = os.Open(tmpFile.Name())
	c.Assert(err, check.IsNil)
	defer tmpFile.Close()

	deleteImages(repoName)

	loadCmd := exec.Command(dockerBinary, "load")
	loadCmd.Stdin = tmpFile

	out, _, err := runCommandWithOutput(loadCmd)
	c.Assert(err, check.IsNil, check.Commentf(out))

	after := inspectField(c, repoName, "Id")
	after = strings.TrimRight(after, "\n")

	c.Assert(after, check.Equals, before) //inspect is not the same after a save / load

	deleteImages(repoName)

	pty, tty, err := pty.Open()
	c.Assert(err, check.IsNil)
	cmd := exec.Command(dockerBinary, "save", repoName)
	cmd.Stdin = tty
	cmd.Stdout = tty
	cmd.Stderr = tty
	c.Assert(cmd.Start(), check.IsNil)
	c.Assert(cmd.Wait(), check.NotNil) //did not break writing to a TTY

	buf := make([]byte, 1024)

	n, err := pty.Read(buf)
	c.Assert(err, check.IsNil) //could not read tty output
	c.Assert(string(buf[:n]), checker.Contains, "Cowardly refusing", check.Commentf("help output is not being yielded", out))
}
Beispiel #22
0
func spawn(cmd *exec.Cmd, ttySpec *garden.TTYSpec, stdout io.Writer, stderr io.Writer) (process, io.WriteCloser, error) {
	var stdin io.WriteCloser
	var err error

	var processPty *os.File

	if ttySpec != nil {
		pty, tty, err := pty.Open()
		if err != nil {
			return nil, nil, err
		}

		// close our end of the tty after the process has spawned
		defer tty.Close()

		processPty = pty
		stdin = pty

		windowColumns := 80
		windowRows := 24
		if ttySpec.WindowSize != nil {
			windowColumns = ttySpec.WindowSize.Columns
			windowRows = ttySpec.WindowSize.Rows
		}

		ptyutil.SetWinSize(pty, windowColumns, windowRows)

		cmd.Stdin = tty
		cmd.Stdout = tty
		cmd.Stderr = tty

		go io.Copy(stdout, pty)
	} else {
		stdin, err = cmd.StdinPipe()
		if err != nil {
			return nil, nil, err
		}

		cmd.Stdout = stdout
		cmd.Stderr = stderr
	}

	err = cmd.Start()
	if err != nil {
		return nil, nil, err
	}

	return &groupProcess{
		process:    cmd.Process,
		processPty: processPty,
	}, stdin, nil
}
// TestAttachDetach checks that attach in tty mode can be detached using the long container ID
func (s *DockerSuite) TestAttachDetach(c *check.C) {
	out, _ := dockerCmd(c, "run", "-itd", "busybox", "cat")
	id := strings.TrimSpace(out)
	c.Assert(waitRun(id), check.IsNil)

	cpty, tty, err := pty.Open()
	c.Assert(err, check.IsNil)
	defer cpty.Close()

	cmd := exec.Command(dockerBinary, "attach", id)
	cmd.Stdin = tty
	stdout, err := cmd.StdoutPipe()
	c.Assert(err, check.IsNil)
	defer stdout.Close()
	err = cmd.Start()
	c.Assert(err, check.IsNil)
	c.Assert(waitRun(id), check.IsNil)

	_, err = cpty.Write([]byte("hello\n"))
	c.Assert(err, check.IsNil)
	out, err = bufio.NewReader(stdout).ReadString('\n')
	c.Assert(err, check.IsNil)
	c.Assert(strings.TrimSpace(out), checker.Equals, "hello", check.Commentf("expected 'hello', got %q", out))

	// escape sequence
	_, err = cpty.Write([]byte{16})
	c.Assert(err, checker.IsNil)
	time.Sleep(100 * time.Millisecond)
	_, err = cpty.Write([]byte{17})
	c.Assert(err, checker.IsNil)

	ch := make(chan struct{})
	go func() {
		cmd.Wait()
		ch <- struct{}{}
	}()

	running, err := inspectField(id, "State.Running")
	c.Assert(err, checker.IsNil)
	c.Assert(running, checker.Equals, "true", check.Commentf("expected container to still be running"))

	go func() {
		dockerCmd(c, "kill", id)
	}()

	select {
	case <-ch:
	case <-time.After(10 * time.Millisecond):
		c.Fatal("timed out waiting for container to exit")
	}

}
Beispiel #24
0
func Open() (PTY, error) {
	p, t, err := pty.Open()
	if err != nil {
		return PTY{}, err
	}

	return PTY{
		TTYR: t,
		TTYW: t,
		PTYR: p,
		PTYW: p,
	}, nil
}
// TestRunDetach checks attaching and detaching with the default escape sequence.
func (s *DockerSuite) TestRunAttachDetach(c *check.C) {
	name := "attach-detach"

	dockerCmd(c, "run", "--name", name, "-itd", "busybox", "cat")

	cmd := exec.Command(dockerBinary, "attach", name)
	stdout, err := cmd.StdoutPipe()
	c.Assert(err, checker.IsNil)
	cpty, tty, err := pty.Open()
	c.Assert(err, checker.IsNil)
	defer cpty.Close()
	cmd.Stdin = tty
	c.Assert(cmd.Start(), checker.IsNil)
	c.Assert(waitRun(name), check.IsNil)

	_, err = cpty.Write([]byte("hello\n"))
	c.Assert(err, checker.IsNil)

	out, err := bufio.NewReader(stdout).ReadString('\n')
	c.Assert(err, checker.IsNil)
	c.Assert(strings.TrimSpace(out), checker.Equals, "hello")

	// escape sequence
	_, err = cpty.Write([]byte{16})
	c.Assert(err, checker.IsNil)
	time.Sleep(100 * time.Millisecond)
	_, err = cpty.Write([]byte{17})
	c.Assert(err, checker.IsNil)

	ch := make(chan struct{})
	go func() {
		cmd.Wait()
		ch <- struct{}{}
	}()

	select {
	case <-ch:
	case <-time.After(10 * time.Second):
		c.Fatal("timed out waiting for container to exit")
	}

	running := inspectField(c, name, "State.Running")
	c.Assert(running, checker.Equals, "true", check.Commentf("expected container to still be running"))

	out, _ = dockerCmd(c, "events", "--since=0", "--until", daemonUnixTime(c), "-f", "container="+name)
	// attach and detach event should be monitored
	c.Assert(out, checker.Contains, "attach")
	c.Assert(out, checker.Contains, "detach")
}
Beispiel #26
0
func NewTtyConsole(command *Command, pipes *Pipes) (*TtyConsole, error) {
	ptyMaster, ptySlave, err := pty.Open()
	if err != nil {
		return nil, err
	}
	tty := &TtyConsole{
		master: ptyMaster,
		slave:  ptySlave,
	}
	if err := tty.attach(command, pipes); err != nil {
		tty.Close()
		return nil, err
	}
	return tty, nil
}
func (s *DockerSuite) TestRunAttachInvalidDetachKeySequencePreserved(c *check.C) {
	name := "attach-detach"
	keyA := []byte{97}
	keyB := []byte{98}

	dockerCmd(c, "run", "--name", name, "-itd", "busybox", "cat")

	cmd := exec.Command(dockerBinary, "attach", "--detach-keys=a,b,c", name)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		c.Fatal(err)
	}
	cpty, tty, err := pty.Open()
	if err != nil {
		c.Fatal(err)
	}
	defer cpty.Close()
	cmd.Stdin = tty
	if err := cmd.Start(); err != nil {
		c.Fatal(err)
	}
	c.Assert(waitRun(name), check.IsNil)

	// Invalid escape sequence aba, should print aba in output
	if _, err := cpty.Write(keyA); err != nil {
		c.Fatal(err)
	}
	time.Sleep(100 * time.Millisecond)
	if _, err := cpty.Write(keyB); err != nil {
		c.Fatal(err)
	}
	time.Sleep(100 * time.Millisecond)
	if _, err := cpty.Write(keyA); err != nil {
		c.Fatal(err)
	}
	time.Sleep(100 * time.Millisecond)
	if _, err := cpty.Write([]byte("\n")); err != nil {
		c.Fatal(err)
	}

	out, err := bufio.NewReader(stdout).ReadString('\n')
	if err != nil {
		c.Fatal(err)
	}
	if strings.TrimSpace(out) != "aba" {
		c.Fatalf("expected 'aba', got %q", out)
	}
}
Beispiel #28
0
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
}
// fail because load didn't receive data from stdin
func (s *DockerSuite) TestLoadNoStdinFail(c *check.C) {
	pty, tty, err := pty.Open()
	c.Assert(err, check.IsNil)
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	cmd := exec.CommandContext(ctx, dockerBinary, "load")
	cmd.Stdin = tty
	cmd.Stdout = tty
	cmd.Stderr = tty
	c.Assert(cmd.Run(), check.NotNil) // docker-load should fail

	buf := make([]byte, 1024)

	n, err := pty.Read(buf)
	c.Assert(err, check.IsNil) //could not read tty output
	c.Assert(string(buf[:n]), checker.Contains, "requested load from stdin, but stdin is empty")
}
// #9860
func TestAttachClosedOnContainerStop(t *testing.T) {
	defer deleteAllContainers()

	cmd := exec.Command(dockerBinary, "run", "-dti", "busybox", "sleep", "2")
	out, _, err := runCommandWithOutput(cmd)
	if err != nil {
		t.Fatalf("failed to start container: %v (%v)", out, err)
	}

	id := stripTrailingCharacters(out)
	if err := waitRun(id); err != nil {
		t.Fatal(err)
	}

	done := make(chan struct{})

	go func() {
		defer close(done)

		_, tty, err := pty.Open()
		if err != nil {
			t.Fatalf("could not open pty: %v", err)
		}
		attachCmd := exec.Command(dockerBinary, "attach", id)
		attachCmd.Stdin = tty
		attachCmd.Stdout = tty
		attachCmd.Stderr = tty

		if err := attachCmd.Run(); err != nil {
			t.Fatalf("attach returned error %s", err)
		}
	}()

	waitCmd := exec.Command(dockerBinary, "wait", id)
	if out, _, err = runCommandWithOutput(waitCmd); err != nil {
		t.Fatalf("error thrown while waiting for container: %s, %v", out, err)
	}
	select {
	case <-done:
	case <-time.After(attachWait):
		t.Fatal("timed out without attach returning")
	}

	logDone("attach - return after container finished")
}