//! getty [-1] DEVICE -- run a shell on another terminal, e.g. /dev/hvc0. //! //! Real Unix systems run one "getty" per terminal line: it opens the line //! and starts a login shell on it. Ours skips the login: it opens DEVICE //! and spawns `sh` with stdin, stdout and stderr all on it. When the shell //! exits (`exit`) a new one starts, unless `-1` was given. //! //! Try it: `getty /dev/hvc0 &` here, then on the host //! `socat - UNIX-CONNECT:target/hvc0.sock` and type commands. That shell //! is not "interactive" (no line editing): it reads one line at a time and //! prints each line after the prompt, like a script. #![no_std] #![no_main] #[macro_use] #[path = "ulib.rs"] mod ulib; use ulib::*; const SHELL: &str = "/mnt/disk0/bin/sh"; fn main() -> i64 { let (once, dev) = match (arg(1), arg(2)) { (Some("-1"), Some(dev)) => (true, dev), (Some(dev), None) if dev != "-1" => (false, dev), _ => { eprintln!("usage: getty [-1] DEVICE (e.g. getty /dev/hvc0 &)"); return 2; } }; loop { let fd = open(dev, 0); if fd < 0 { eprintln!("getty: {}: {}", dev, strerror(fd)); return 1; } let greeting = "\nRustbelt getty: shell on this terminal (type `exit` to end it)\n"; write(fd, greeting.as_bytes()); let opts = SpawnOptions { stdin: fd, stdout: fd, stderr: fd, flags: 0 }; let pid = spawn(SHELL, "sh", &opts); if pid < 0 { eprintln!("getty: {}: {}", SHELL, strerror(pid)); close(fd); return 1; } let status = wait(pid); close(fd); if once { return status; } sleep_ms(500); // don't spin if the shell keeps dying at once } }