util_solaris.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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. state *unix.Termios
  14. }
  15. // IsTerminal returns true if 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. oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS)
  68. if err != nil {
  69. return nil, err
  70. }
  71. oldTermios := *oldTermiosPtr
  72. newTermios := oldTermios
  73. newTermios.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON
  74. newTermios.Oflag &^= syscall.OPOST
  75. newTermios.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN
  76. newTermios.Cflag &^= syscall.CSIZE | syscall.PARENB
  77. newTermios.Cflag |= syscall.CS8
  78. newTermios.Cc[unix.VMIN] = 1
  79. newTermios.Cc[unix.VTIME] = 0
  80. if err := unix.IoctlSetTermios(fd, unix.TCSETS, &newTermios); err != nil {
  81. return nil, err
  82. }
  83. return &State{
  84. state: oldTermiosPtr,
  85. }, nil
  86. }
  87. // Restore restores the terminal connected to the given file descriptor to a
  88. // previous state.
  89. func Restore(fd int, oldState *State) error {
  90. return unix.IoctlSetTermios(fd, unix.TCSETS, oldState.state)
  91. }
  92. // GetState returns the current state of a terminal which may be useful to
  93. // restore the terminal after a signal.
  94. func GetState(fd int) (*State, error) {
  95. oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS)
  96. if err != nil {
  97. return nil, err
  98. }
  99. return &State{
  100. state: oldTermiosPtr,
  101. }, nil
  102. }
  103. // GetSize returns the dimensions of the given terminal.
  104. func GetSize(fd int) (width, height int, err error) {
  105. ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
  106. if err != nil {
  107. return 0, 0, err
  108. }
  109. return int(ws.Col), int(ws.Row), nil
  110. }