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