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 5package term 6 7import ( 8 "io" 9 "syscall" 10 11 "golang.org/x/sys/unix" 12) 13 14// State contains the state of a terminal. 15type state struct { 16 termios unix.Termios 17} 18 19func isTerminal(fd int) bool { 20 _, err := unix.IoctlGetTermio(fd, unix.TCGETA) 21 return err == nil 22} 23 24func readPassword(fd int) ([]byte, error) { 25 // see also: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c 26 val, err := unix.IoctlGetTermios(fd, unix.TCGETS) 27 if err != nil { 28 return nil, err 29 } 30 oldState := *val 31 32 newState := oldState 33 newState.Lflag &^= syscall.ECHO 34 newState.Lflag |= syscall.ICANON | syscall.ISIG 35 newState.Iflag |= syscall.ICRNL 36 err = unix.IoctlSetTermios(fd, unix.TCSETS, &newState) 37 if err != nil { 38 return nil, err 39 } 40 41 defer unix.IoctlSetTermios(fd, unix.TCSETS, &oldState) 42 43 var buf [16]byte 44 var ret []byte 45 for { 46 n, err := syscall.Read(fd, buf[:]) 47 if err != nil { 48 return nil, err 49 } 50 if n == 0 { 51 if len(ret) == 0 { 52 return nil, io.EOF 53 } 54 break 55 } 56 if buf[n-1] == '\n' { 57 n-- 58 } 59 ret = append(ret, buf[:n]...) 60 if n < len(buf) { 61 break 62 } 63 } 64 65 return ret, nil 66} 67 68func makeRaw(fd int) (*State, error) { 69 // see http://cr.illumos.org/~webrev/andy_js/1060/ 70 termios, err := unix.IoctlGetTermios(fd, unix.TCGETS) 71 if err != nil { 72 return nil, err 73 } 74 75 oldState := State{state{termios: *termios}} 76 77 termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON 78 termios.Oflag &^= unix.OPOST 79 termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN 80 termios.Cflag &^= unix.CSIZE | unix.PARENB 81 termios.Cflag |= unix.CS8 82 termios.Cc[unix.VMIN] = 1 83 termios.Cc[unix.VTIME] = 0 84 85 if err := unix.IoctlSetTermios(fd, unix.TCSETS, termios); err != nil { 86 return nil, err 87 } 88 89 return &oldState, nil 90} 91 92func restore(fd int, oldState *State) error { 93 return unix.IoctlSetTermios(fd, unix.TCSETS, &oldState.termios) 94} 95 96func getState(fd int) (*State, error) { 97 termios, err := unix.IoctlGetTermios(fd, unix.TCGETS) 98 if err != nil { 99 return nil, err 100 } 101 102 return &State{state{termios: *termios}}, nil 103} 104 105func getSize(fd int) (width, height int, err error) { 106 ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) 107 if err != nil { 108 return 0, 0, err 109 } 110 return int(ws.Col), int(ws.Row), nil 111} 112