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 5//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos 6// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos 7 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} 93