You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

term_unix.go 2.4KB

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