util_solaris.go 3.2 KB

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