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 { 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 io::Result>(f: F) -> io::Result { 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 { 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) }) }