1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
extern crate libc;
use std::io::{self, Write};
use std::mem;
use std::str;
fn error_checker(ret: i32) -> io::Result<()> {
if ret == 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
fn tcgetattr(fd: i32) -> io::Result<libc::termios> {
unsafe {
let mut tios: libc::termios = mem::zeroed();
error_checker(libc::tcgetattr(fd, &mut tios))?;
Ok(tios)
}
}
fn tcsetattr(fd: i32, other_options: i32, tios: &libc::termios) -> io::Result<()> {
unsafe {
error_checker(libc::tcsetattr(fd, other_options, tios))?;
Ok(())
}
}
fn without_echo<T, F: FnOnce() -> io::Result<T>>(f: F) -> io::Result<T> {
let tios_old = tcgetattr(0)?;
let mut tios_new = tios_old;
tios_new.c_lflag &= !libc::ECHO;
tios_new.c_lflag |= libc::ECHONL;
match tcsetattr(0, libc::TCSANOW, &tios_new) {
Ok(()) => {},
Err(e) => {
// Just blindly try to reset the terminal, in case something changed
let _ = tcsetattr(0, libc::TCSANOW, &tios_old);
return Err(e);
}
}
let ret = f()?;
tcsetattr(0, libc::TCSANOW, &tios_old)?;
Ok(ret)
}
pub fn get_pass(prompt: &str) -> io::Result<String> {
print!("{}", prompt);
io::stdout().flush()?;
without_echo(|| {
let mut line = String::new();
io::stdin().read_line(&mut line)?;
if line.ends_with('\n') {
line.pop();
}
Ok(line)
})
}
|