예제 #1
0
func pipePty(cmd *exec.Cmd, handler *interactive.ShellHandler) error {
	// Start the shell as TTY
	f, err := pty.Start(cmd)
	if err == nil {
		// Connect pipes (close stderr as tty only has two streams)
		go ioext.CopyAndClose(f, handler.StdinPipe())
		go ioext.CopyAndClose(handler.StdoutPipe(), f)
		go handler.StderrPipe().Close()

		// Start communication
		handler.Communicate(func(cols, rows uint16) error {
			return setTTYSize(f, cols, rows)
		}, func() error {
			if cmd.Process != nil {
				return cmd.Process.Kill()
			}
			return nil
		})
	}
	// If pty wasn't supported for some reason we fall back to normal execution
	if err == pty.ErrUnsupported {
		return pipeCommand(cmd, handler)
	}
	if err != nil {
		handler.Communicate(nil, func() error {
			// If cmd.Start() failed, then we don't have a process, but we start
			// the communication flow anyways.
			if cmd.Process != nil {
				return cmd.Process.Kill()
			}
			return nil
		})
	}
	return err
}
예제 #2
0
func pipeCommand(cmd *exec.Cmd, handler *interactive.ShellHandler) error {
	// Set pipes
	cmd.Stdin = handler.StdinPipe()
	cmd.Stdout = handler.StdoutPipe()
	cmd.Stderr = handler.StderrPipe()

	// Start the shell, this must finished before we can call Kill()
	err := cmd.Start()

	// Start communication
	handler.Communicate(nil, func() error {
		// If cmd.Start() failed, then we don't have a process, but we start
		// the communication flow anyways.
		if cmd.Process != nil {
			return cmd.Process.Kill()
		}
		return nil
	})

	return err
}