aboutsummaryrefslogtreecommitdiff
path: root/rust/src/getpass.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src/getpass.rs')
-rw-r--r--rust/src/getpass.rs65
1 files changed, 65 insertions, 0 deletions
diff --git a/rust/src/getpass.rs b/rust/src/getpass.rs
new file mode 100644
index 0000000..f40da0e
--- /dev/null
+++ b/rust/src/getpass.rs
@@ -0,0 +1,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)
+ })
+}