term_unix.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
  2. // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
  3. package term
  4. import (
  5. "golang.org/x/sys/unix"
  6. )
  7. type state struct {
  8. unix.Termios
  9. }
  10. func isTerminal(fd uintptr) bool {
  11. _, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios)
  12. return err == nil
  13. }
  14. func makeRaw(fd uintptr) (*State, error) {
  15. termios, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios)
  16. if err != nil {
  17. return nil, err
  18. }
  19. oldState := State{state{Termios: *termios}}
  20. // This attempts to replicate the behaviour documented for cfmakeraw in
  21. // the termios(3) manpage.
  22. termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
  23. termios.Oflag &^= unix.OPOST
  24. termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
  25. termios.Cflag &^= unix.CSIZE | unix.PARENB
  26. termios.Cflag |= unix.CS8
  27. termios.Cc[unix.VMIN] = 1
  28. termios.Cc[unix.VTIME] = 0
  29. if err := unix.IoctlSetTermios(int(fd), ioctlWriteTermios, termios); err != nil {
  30. return nil, err
  31. }
  32. return &oldState, nil
  33. }
  34. func setState(fd uintptr, state *State) error {
  35. var termios *unix.Termios
  36. if state != nil {
  37. termios = &state.Termios
  38. }
  39. return unix.IoctlSetTermios(int(fd), ioctlWriteTermios, termios)
  40. }
  41. func getState(fd uintptr) (*State, error) {
  42. termios, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios)
  43. if err != nil {
  44. return nil, err
  45. }
  46. return &State{state{Termios: *termios}}, nil
  47. }
  48. func restore(fd uintptr, state *State) error {
  49. return unix.IoctlSetTermios(int(fd), ioctlWriteTermios, &state.Termios)
  50. }
  51. func getSize(fd uintptr) (width, height int, err error) {
  52. ws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ)
  53. if err != nil {
  54. return 0, 0, err
  55. }
  56. return int(ws.Col), int(ws.Row), nil
  57. }
  58. // passwordReader is an io.Reader that reads from a specific file descriptor.
  59. type passwordReader int
  60. func (r passwordReader) Read(buf []byte) (int, error) {
  61. return unix.Read(int(r), buf)
  62. }
  63. func readPassword(fd uintptr) ([]byte, error) {
  64. termios, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios)
  65. if err != nil {
  66. return nil, err
  67. }
  68. newState := *termios
  69. newState.Lflag &^= unix.ECHO
  70. newState.Lflag |= unix.ICANON | unix.ISIG
  71. newState.Iflag |= unix.ICRNL
  72. if err := unix.IoctlSetTermios(int(fd), ioctlWriteTermios, &newState); err != nil {
  73. return nil, err
  74. }
  75. defer unix.IoctlSetTermios(int(fd), ioctlWriteTermios, termios)
  76. return readPasswordLine(passwordReader(fd))
  77. }