1// Copyright 2011 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// +build aix darwin dragonfly freebsd linux,!appengine netbsd openbsd 6 7// Package terminal provides support functions for dealing with terminals, as 8// commonly found on UNIX systems. 9// 10// Putting a terminal into raw mode is the most common requirement: 11// 12// oldState, err := terminal.MakeRaw(0) 13// if err != nil { 14// panic(err) 15// } 16// defer terminal.Restore(0, oldState) 17package terminal // import "golang.org/x/crypto/ssh/terminal" 18 19import ( 20 "golang.org/x/sys/unix" 21) 22 23// State contains the state of a terminal. 24type State struct { 25 termios unix.Termios 26} 27 28// IsTerminal returns whether the given file descriptor is a terminal. 29func IsTerminal(fd int) bool { 30 _, err := unix.IoctlGetTermios(fd, ioctlReadTermios) 31 return err == nil 32} 33 34// MakeRaw put the terminal connected to the given file descriptor into raw 35// mode and returns the previous state of the terminal so that it can be 36// restored. 37func MakeRaw(fd int) (*State, error) { 38 termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) 39 if err != nil { 40 return nil, err 41 } 42 43 oldState := State{termios: *termios} 44 45 // This attempts to replicate the behaviour documented for cfmakeraw in 46 // the termios(3) manpage. 47 termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON 48 termios.Oflag &^= unix.OPOST 49 termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN 50 termios.Cflag &^= unix.CSIZE | unix.PARENB 51 termios.Cflag |= unix.CS8 52 termios.Cc[unix.VMIN] = 1 53 termios.Cc[unix.VTIME] = 0 54 if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, termios); err != nil { 55 return nil, err 56 } 57 58 return &oldState, nil 59} 60 61// GetState returns the current state of a terminal which may be useful to 62// restore the terminal after a signal. 63func GetState(fd int) (*State, error) { 64 termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) 65 if err != nil { 66 return nil, err 67 } 68 69 return &State{termios: *termios}, nil 70} 71 72// Restore restores the terminal connected to the given file descriptor to a 73// previous state. 74func Restore(fd int, state *State) error { 75 return unix.IoctlSetTermios(fd, ioctlWriteTermios, &state.termios) 76} 77 78// GetSize returns the dimensions of the given terminal. 79func GetSize(fd int) (width, height int, err error) { 80 ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) 81 if err != nil { 82 return -1, -1, err 83 } 84 return int(ws.Col), int(ws.Row), nil 85} 86 87// passwordReader is an io.Reader that reads from a specific file descriptor. 88type passwordReader int 89 90func (r passwordReader) Read(buf []byte) (int, error) { 91 return unix.Read(int(r), buf) 92} 93 94// ReadPassword reads a line of input from a terminal without local echo. This 95// is commonly used for inputting passwords and other sensitive data. The slice 96// returned does not include the \n. 97func ReadPassword(fd int) ([]byte, error) { 98 termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) 99 if err != nil { 100 return nil, err 101 } 102 103 newState := *termios 104 newState.Lflag &^= unix.ECHO 105 newState.Lflag |= unix.ICANON | unix.ISIG 106 newState.Iflag |= unix.ICRNL 107 if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, &newState); err != nil { 108 return nil, err 109 } 110 111 defer unix.IoctlSetTermios(fd, ioctlWriteTermios, termios) 112 113 return readPasswordLine(passwordReader(fd)) 114} 115