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