~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/golang.org/x/crypto/ssh/terminal/util.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 // import "golang.org/x/crypto/ssh/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
}