github.com/glycerine/xcryptossh@v7.0.4+incompatible/terminal/util_solaris.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build solaris
     6  
     7  package terminal
     8  
     9  import (
    10  	"golang.org/x/sys/unix"
    11  	"io"
    12  	"syscall"
    13  )
    14  
    15  // State contains the state of a terminal.
    16  type State struct {
    17  	state *unix.Termios
    18  }
    19  
    20  // IsTerminal returns true if the given file descriptor is a terminal.
    21  func IsTerminal(fd int) bool {
    22  	_, err := unix.IoctlGetTermio(fd, unix.TCGETA)
    23  	return err == nil
    24  }
    25  
    26  // ReadPassword reads a line of input from a terminal without local echo.  This
    27  // is commonly used for inputting passwords and other sensitive data. The slice
    28  // returned does not include the \n.
    29  func ReadPassword(fd int) ([]byte, error) {
    30  	// see also: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c
    31  	val, err := unix.IoctlGetTermios(fd, unix.TCGETS)
    32  	if err != nil {
    33  		return nil, err
    34  	}
    35  	oldState := *val
    36  
    37  	newState := oldState
    38  	newState.Lflag &^= syscall.ECHO
    39  	newState.Lflag |= syscall.ICANON | syscall.ISIG
    40  	newState.Iflag |= syscall.ICRNL
    41  	err = unix.IoctlSetTermios(fd, unix.TCSETS, &newState)
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  
    46  	defer unix.IoctlSetTermios(fd, unix.TCSETS, &oldState)
    47  
    48  	var buf [16]byte
    49  	var ret []byte
    50  	for {
    51  		n, err := syscall.Read(fd, buf[:])
    52  		if err != nil {
    53  			return nil, err
    54  		}
    55  		if n == 0 {
    56  			if len(ret) == 0 {
    57  				return nil, io.EOF
    58  			}
    59  			break
    60  		}
    61  		if buf[n-1] == '\n' {
    62  			n--
    63  		}
    64  		ret = append(ret, buf[:n]...)
    65  		if n < len(buf) {
    66  			break
    67  		}
    68  	}
    69  
    70  	return ret, nil
    71  }
    72  
    73  // MakeRaw puts the terminal connected to the given file descriptor into raw
    74  // mode and returns the previous state of the terminal so that it can be
    75  // restored.
    76  // see http://cr.illumos.org/~webrev/andy_js/1060/
    77  func MakeRaw(fd int) (*State, error) {
    78  	oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS)
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  	oldTermios := *oldTermiosPtr
    83  
    84  	newTermios := oldTermios
    85  	newTermios.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON
    86  	newTermios.Oflag &^= syscall.OPOST
    87  	newTermios.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN
    88  	newTermios.Cflag &^= syscall.CSIZE | syscall.PARENB
    89  	newTermios.Cflag |= syscall.CS8
    90  	newTermios.Cc[unix.VMIN] = 1
    91  	newTermios.Cc[unix.VTIME] = 0
    92  
    93  	if err := unix.IoctlSetTermios(fd, unix.TCSETS, &newTermios); err != nil {
    94  		return nil, err
    95  	}
    96  
    97  	return &State{
    98  		state: oldTermiosPtr,
    99  	}, nil
   100  }
   101  
   102  // Restore restores the terminal connected to the given file descriptor to a
   103  // previous state.
   104  func Restore(fd int, oldState *State) error {
   105  	return unix.IoctlSetTermios(fd, unix.TCSETS, oldState.state)
   106  }
   107  
   108  // GetState returns the current state of a terminal which may be useful to
   109  // restore the terminal after a signal.
   110  func GetState(fd int) (*State, error) {
   111  	oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  
   116  	return &State{
   117  		state: oldTermiosPtr,
   118  	}, nil
   119  }
   120  
   121  // GetSize returns the dimensions of the given terminal.
   122  func GetSize(fd int) (width, height int, err error) {
   123  	ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
   124  	if err != nil {
   125  		return 0, 0, err
   126  	}
   127  	return int(ws.Col), int(ws.Row), nil
   128  }