ssh/terminal: store termios copy in terminal state on Solaris

TestMakeRawState currently fails on Solaris:

  --- FAIL: TestMakeRawState (0.00s)
          terminal_test.go:334: states do not match; was &{0xc420015dd0}, expected &{0xc420015da0}

Change terminal.State to include a copy to the unix.Termios (like the
implementation for Linux and the BSDs) which also makes terminal.MakeRaw behave
as expected and lets TestMakeRawState pass.

Change-Id: I29382f83b84ff301991e1db170f32f41e144aec8
Reviewed-on: https://go-review.googlesource.com/99456
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/ssh/terminal/util_solaris.go b/ssh/terminal/util_solaris.go
index a2e1b57..9e41b9f 100644
--- a/ssh/terminal/util_solaris.go
+++ b/ssh/terminal/util_solaris.go
@@ -14,7 +14,7 @@
 
 // State contains the state of a terminal.
 type State struct {
-	state *unix.Termios
+	termios unix.Termios
 }
 
 // IsTerminal returns true if the given file descriptor is a terminal.
@@ -75,47 +75,43 @@
 // restored.
 // see http://cr.illumos.org/~webrev/andy_js/1060/
 func MakeRaw(fd int) (*State, error) {
-	oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS)
+	termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
 	if err != nil {
 		return nil, err
 	}
-	oldTermios := *oldTermiosPtr
 
-	newTermios := oldTermios
-	newTermios.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON
-	newTermios.Oflag &^= syscall.OPOST
-	newTermios.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN
-	newTermios.Cflag &^= syscall.CSIZE | syscall.PARENB
-	newTermios.Cflag |= syscall.CS8
-	newTermios.Cc[unix.VMIN] = 1
-	newTermios.Cc[unix.VTIME] = 0
+	oldState := State{termios: *termios}
 
-	if err := unix.IoctlSetTermios(fd, unix.TCSETS, &newTermios); err != nil {
+	termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
+	termios.Oflag &^= unix.OPOST
+	termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
+	termios.Cflag &^= unix.CSIZE | unix.PARENB
+	termios.Cflag |= unix.CS8
+	termios.Cc[unix.VMIN] = 1
+	termios.Cc[unix.VTIME] = 0
+
+	if err := unix.IoctlSetTermios(fd, unix.TCSETS, termios); err != nil {
 		return nil, err
 	}
 
-	return &State{
-		state: oldTermiosPtr,
-	}, nil
+	return &oldState, nil
 }
 
 // Restore restores the terminal connected to the given file descriptor to a
 // previous state.
 func Restore(fd int, oldState *State) error {
-	return unix.IoctlSetTermios(fd, unix.TCSETS, oldState.state)
+	return unix.IoctlSetTermios(fd, unix.TCSETS, &oldState.termios)
 }
 
 // GetState returns the current state of a terminal which may be useful to
 // restore the terminal after a signal.
 func GetState(fd int) (*State, error) {
-	oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS)
+	termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
 	if err != nil {
 		return nil, err
 	}
 
-	return &State{
-		state: oldTermiosPtr,
-	}, nil
+	return &State{termios: *termios}, nil
 }
 
 // GetSize returns the dimensions of the given terminal.