ssh/terminal: implement missing functions for Solaris/OmniOS
terminal.MakeRaw
terminal.Restore
terminal.GetState
terminal.GetSize
Fixes golang/go#20062
@@ -14,14 +14,12 @@ import (
// State contains the state of a terminal.
type State struct {
- termios syscall.Termios
+ state *unix.Termios
}
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
- // see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c
- var termio unix.Termio
- err := unix.IoctlSetTermio(fd, unix.TCGETA, &termio)
+ _, err := unix.IoctlGetTermio(fd, unix.TCGETA)
return err == nil
}
@@ -71,3 +69,60 @@ func ReadPassword(fd int) ([]byte, error) {
return ret, nil
}
+
+// MakeRaw puts the terminal connected to the given file descriptor into raw
+// mode and returns the previous state of the terminal so that it can be
+// restored.
+// see http://cr.illumos.org/~webrev/andy_js/1060/
+func MakeRaw(fd int) (*State, error) {
+ oldTermiosPtr, 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
+
+ if err := unix.IoctlSetTermios(fd, unix.TCSETS, &newTermios); err != nil {
+ return nil, err
+ }
+
+ return &State{
+ state: oldTermiosPtr,
+ }, 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)
+}
+
+// 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)
+ if err != nil {
+ return nil, err
+ }
+
+ return &State{
+ state: oldTermiosPtr,
+ }, nil
+}
+
+// GetSize returns the dimensions of the given terminal.
+func GetSize(fd int) (width, height int, err error) {
+ ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
+ if err != nil {
+ return 0, 0, err
+ }
+ return int(ws.Col), int(ws.Row), nil
+}
