84 lines
2.1 KiB
Rust

#![feature(yggdrasil_os, yggdrasil_raw_fd, rustc_private)]
use std::{
env,
io::{self, stdin, stdout, BufRead, Write},
os::{
fd::AsRawFd,
yggdrasil::io::{
device::{DeviceRequest, FdDeviceRequest},
terminal::start_terminal_session,
},
},
process::{self, Command, ExitCode},
};
fn login_readline<R: BufRead + AsRawFd>(
reader: &mut R,
buf: &mut String,
_secret: bool,
) -> Result<usize, io::Error> {
reader.read_line(buf)
}
fn login_as(username: &str, _password: &str) -> Result<(), io::Error> {
let mut shell = Command::new("/bin/sh").arg("-l").spawn()?;
println!("Hello {:?}", username);
shell.wait()?;
Ok(())
}
fn login_attempt(erase: bool) -> Result<(), io::Error> {
let mut stdin = stdin().lock();
let mut stdout = stdout();
if erase {
print!("\x1b[1;1f\x1b[2J");
stdout.flush().ok();
}
let mut username = String::new();
print!("Username: ");
stdout.flush().ok();
if login_readline(&mut stdin, &mut username, false)? == 0 {
return Ok(());
}
login_as(username.trim(), "")
}
fn main() -> ExitCode {
let args: Vec<_> = env::args().skip(1).collect();
if args.len() != 1 {
eprintln!("Usage: /sbin/login TTY");
return ExitCode::FAILURE;
}
let terminal = args[0].as_str();
// TODO check that `terminal` is a terminal
debug_trace!("Starting a session at {}", terminal);
if let Err(err) = unsafe { start_terminal_session(terminal) } {
debug_trace!("Error: {:?}", err);
eprintln!("Could not setup a session at {}: {:?}", terminal, err);
return ExitCode::FAILURE;
}
let mut attempt_number = 0;
loop {
debug_trace!("Login attempt {}", attempt_number);
// "Attach" the terminal
unsafe {
stdin()
.device_request(&mut DeviceRequest::SetTerminalGroup(process::id()))
.expect("Could not attach the terminal");
}
if let Err(err) = login_attempt(attempt_number % 3 == 0) {
eprintln!("login: {}", err.to_string());
}
attempt_number += 1;
}
}