github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/golang.org/x/crypto/ssh/terminal/util.go (about) 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 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) 17 package terminal 18 19 import ( 20 "io" 21 "syscall" 22 "unsafe" 23 ) 24 25 // State contains the state of a terminal. 26 type State struct { 27 termios syscall.Termios 28 } 29 30 // IsTerminal returns true if the given file descriptor is a terminal. 31 func IsTerminal(fd int) bool { 32 var termios syscall.Termios 33 _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) 34 return err == 0 35 } 36 37 // MakeRaw put the terminal connected to the given file descriptor into raw 38 // mode and returns the previous state of the terminal so that it can be 39 // restored. 40 func MakeRaw(fd int) (*State, error) { 41 var oldState State 42 if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { 43 return nil, err 44 } 45 46 newState := oldState.termios 47 newState.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF 48 newState.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG 49 if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { 50 return nil, err 51 } 52 53 return &oldState, nil 54 } 55 56 // GetState returns the current state of a terminal which may be useful to 57 // restore the terminal after a signal. 58 func GetState(fd int) (*State, error) { 59 var oldState State 60 if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { 61 return nil, err 62 } 63 64 return &oldState, nil 65 } 66 67 // Restore restores the terminal connected to the given file descriptor to a 68 // previous state. 69 func Restore(fd int, state *State) error { 70 _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0) 71 return err 72 } 73 74 // GetSize returns the dimensions of the given terminal. 75 func GetSize(fd int) (width, height int, err error) { 76 var dimensions [4]uint16 77 78 if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0); err != 0 { 79 return -1, -1, err 80 } 81 return int(dimensions[1]), int(dimensions[0]), nil 82 } 83 84 // ReadPassword reads a line of input from a terminal without local echo. This 85 // is commonly used for inputting passwords and other sensitive data. The slice 86 // returned does not include the \n. 87 func ReadPassword(fd int) ([]byte, error) { 88 var oldState syscall.Termios 89 if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); err != 0 { 90 return nil, err 91 } 92 93 newState := oldState 94 newState.Lflag &^= syscall.ECHO 95 newState.Lflag |= syscall.ICANON | syscall.ISIG 96 newState.Iflag |= syscall.ICRNL 97 if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { 98 return nil, err 99 } 100 101 defer func() { 102 syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0) 103 }() 104 105 var buf [16]byte 106 var ret []byte 107 for { 108 n, err := syscall.Read(fd, buf[:]) 109 if err != nil { 110 return nil, err 111 } 112 if n == 0 { 113 if len(ret) == 0 { 114 return nil, io.EOF 115 } 116 break 117 } 118 if buf[n-1] == '\n' { 119 n-- 120 } 121 ret = append(ret, buf[:n]...) 122 if n < len(buf) { 123 break 124 } 125 } 126 127 return ret, nil 128 }