aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/bgentry/speakeasy/speakeasy_unix.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/bgentry/speakeasy/speakeasy_unix.go')
-rw-r--r--vendor/github.com/bgentry/speakeasy/speakeasy_unix.go93
1 files changed, 93 insertions, 0 deletions
diff --git a/vendor/github.com/bgentry/speakeasy/speakeasy_unix.go b/vendor/github.com/bgentry/speakeasy/speakeasy_unix.go
new file mode 100644
index 0000000..d99fda1
--- /dev/null
+++ b/vendor/github.com/bgentry/speakeasy/speakeasy_unix.go
@@ -0,0 +1,93 @@
1// based on https://code.google.com/p/gopass
2// Author: johnsiilver@gmail.com (John Doak)
3//
4// Original code is based on code by RogerV in the golang-nuts thread:
5// https://groups.google.com/group/golang-nuts/browse_thread/thread/40cc41e9d9fc9247
6
7// +build darwin dragonfly freebsd linux netbsd openbsd solaris
8
9package speakeasy
10
11import (
12 "fmt"
13 "os"
14 "os/signal"
15 "strings"
16 "syscall"
17)
18
19const sttyArg0 = "/bin/stty"
20
21var (
22 sttyArgvEOff = []string{"stty", "-echo"}
23 sttyArgvEOn = []string{"stty", "echo"}
24)
25
26// getPassword gets input hidden from the terminal from a user. This is
27// accomplished by turning off terminal echo, reading input from the user and
28// finally turning on terminal echo.
29func getPassword() (password string, err error) {
30 sig := make(chan os.Signal, 10)
31 brk := make(chan bool)
32
33 // File descriptors for stdin, stdout, and stderr.
34 fd := []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()}
35
36 // Setup notifications of termination signals to channel sig, create a process to
37 // watch for these signals so we can turn back on echo if need be.
38 signal.Notify(sig, syscall.SIGHUP, syscall.SIGINT, syscall.SIGKILL, syscall.SIGQUIT,
39 syscall.SIGTERM)
40 go catchSignal(fd, sig, brk)
41
42 // Turn off the terminal echo.
43 pid, err := echoOff(fd)
44 if err != nil {
45 return "", err
46 }
47
48 // Turn on the terminal echo and stop listening for signals.
49 defer signal.Stop(sig)
50 defer close(brk)
51 defer echoOn(fd)
52
53 syscall.Wait4(pid, nil, 0, nil)
54
55 line, err := readline()
56 if err == nil {
57 password = strings.TrimSpace(line)
58 } else {
59 err = fmt.Errorf("failed during password entry: %s", err)
60 }
61
62 return password, err
63}
64
65// echoOff turns off the terminal echo.
66func echoOff(fd []uintptr) (int, error) {
67 pid, err := syscall.ForkExec(sttyArg0, sttyArgvEOff, &syscall.ProcAttr{Dir: "", Files: fd})
68 if err != nil {
69 return 0, fmt.Errorf("failed turning off console echo for password entry:\n\t%s", err)
70 }
71 return pid, nil
72}
73
74// echoOn turns back on the terminal echo.
75func echoOn(fd []uintptr) {
76 // Turn on the terminal echo.
77 pid, e := syscall.ForkExec(sttyArg0, sttyArgvEOn, &syscall.ProcAttr{Dir: "", Files: fd})
78 if e == nil {
79 syscall.Wait4(pid, nil, 0, nil)
80 }
81}
82
83// catchSignal tries to catch SIGKILL, SIGQUIT and SIGINT so that we can turn
84// terminal echo back on before the program ends. Otherwise the user is left
85// with echo off on their terminal.
86func catchSignal(fd []uintptr, sig chan os.Signal, brk chan bool) {
87 select {
88 case <-sig:
89 echoOn(fd)
90 os.Exit(-1)
91 case <-brk:
92 }
93}