use std::process::{Command, Stdio}; mod builtins; mod prompt; fn sigint_handler(dummy: i32) { println!("sigint_handler: {}", dummy); } fn main() { unsafe { // capture Ctrl+C (SIGINT) libc::signal(libc::SIGINT, sigint_handler as libc::sighandler_t); } match std::fs::read_to_string("/etc/motd") { Ok(motd) => print!("{}", motd), Err(_) => {} } let prompt = prompt::Prompt::new().unwrap(); let mut cwd = std::env::current_dir().unwrap(); loop { prompt.print(&cwd); let mut input = String::new(); match std::io::stdin().read_line(&mut input) { Ok(0) => return, // EOF Ok(_) => {} // okay Err(e) => { eprintln!("error reading line: {}", e); return; } }; let mut commands = input.trim().split(" | ").peekable(); let mut previous_command: std::option::Option = None; while let Some(command) = commands.next() { let mut parts = command.trim().split_whitespace(); let command = match parts.next() { Some(cmd) => cmd, None => break, }; let args = parts; match command { "cd" => { cwd = builtins::cd(args); previous_command = None; } "exit" => return, command => { let stdin = match previous_command { None => Stdio::inherit(), Some(cmd) => Stdio::from(cmd.stdout.unwrap()), }; let stdout = match commands.peek().is_some() { true => Stdio::piped(), false => Stdio::inherit(), }; let child = Command::new(command) .args(args) .stdin(stdin) .stdout(stdout) .spawn(); match child { Ok(c) => previous_command = Some(c), Err(e) => { previous_command = None; eprintln!("{}", e); } } } } } if let Some(mut final_command) = previous_command { match final_command.wait() { Ok(ret) => match ret.code() { Some(code) => { if cfg!(debug_assertions) { println!("exit code [{}]", code); } } None => println!("Process termed by signal"), }, Err(e) => eprintln!("error waiting on final command: {}", e), } } } // loop }