commit ac86bb7844b756ad2e6e2d52daa469cc6935bc4b Author: Lukáš Hozda Date: Thu Sep 26 13:31:27 2019 +0200 initial initrs commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..53eaa21 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +**/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..3603c1d --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,80 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "arc-swap" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cc" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "initrs" +version = "0.1.0" +dependencies = [ + "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "signal-hook 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "nix" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "signal-hook" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "signal-hook-registry 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "signal-hook-registry" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arc-swap 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum arc-swap 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f1a1eca3195b729bbd64e292ef2f5fff6b1c28504fed762ce2b1013dde4d8e92" +"checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2" +"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" +"checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" +"checksum signal-hook 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4f61c4d59f3aaa9f61bba6450a9b80ba48362fd7d651689e7a10c453b1f6dc68" +"checksum signal-hook-registry 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1797d48f38f91643908bb14e35e79928f9f4b3cefb2420a564dde0991b4358dc" +"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..8dc3af1 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "initrs" +version = "0.1.0" +authors = ["Lukáš Hozda "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +signal-hook = "0.1.10" +nix = "0.15" diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..608b2c0 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,5 @@ +pub static TIMEOUT: u32 = 30; + +pub static INIT_CMD: &'static [&'static str] = &["/bin/rc.init"]; +pub static REBOOT_CMD: &'static [&'static str] = &["/bin/rc.shutdown", "reboot"]; +pub static POWEROFF_CMD: &'static [&'static str] = &["/bin/rc.init", "poweroff"]; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..bf16330 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,90 @@ +extern crate signal_hook; + +use std::thread; +use std::env::set_current_dir; +use std::process::{Stdio, Command}; + +use nix::unistd::{alarm, Pid, getpid}; +use nix::sys::wait::{waitpid, WaitStatus, WaitPidFlag}; +use signal_hook::{iterator::Signals, SIGINT, SIGALRM, SIGCHLD, SIGUSR1}; + +mod config; + +fn sig_poweroff() { + if Command::new(config::POWEROFF_CMD[0]) + .args(config::POWEROFF_CMD.iter().skip(1)) + .output() + .is_err() + { + println!("[RS] poweroff failed"); + } +} + +fn sig_reap() { + loop { + match waitpid(Pid::from_raw(-1), Some(WaitPidFlag::WNOHANG)) { + Err(_) => break, + Ok(status) => match status { + WaitStatus::Exited(pid, ..) | + WaitStatus::Signaled(pid, ..) | + WaitStatus::Stopped(pid, ..) | + WaitStatus::Continued(pid) => if pid.as_raw() <= 0 { + break + }, + _ => (), + } + } + } + + alarm::set(config::TIMEOUT); +} + +fn sig_reboot() { + if Command::new(config::REBOOT_CMD[0]) + .args(config::REBOOT_CMD.iter().skip(1)) + .output() + .is_err() + { + println!("[RS] reboot failed"); + } +} + +fn main() { + if getpid().as_raw() != 1 { return } + + let signals = Signals::new(&[ + SIGUSR1, + SIGCHLD, + SIGALRM, + SIGINT, + ]).expect("[RS] failed to handle signals"); + + set_current_dir("/") + .expect("[RS] failed to chdir"); + + let init = Command::new(config::INIT_CMD[0]) + .args(config::INIT_CMD.iter().skip(1)) + .stderr(Stdio::piped()) + .spawn() + .expect("[RS] failed to spawn init command"); + + thread::spawn(|| { + let c = init.wait_with_output() + .expect("[RS] failed to wait on init command"); + + if !c.status.success() { + eprintln!("[RS] exited with a non-zero return code, see stderr below:"); + eprintln!("{}", String::from_utf8_lossy(&c.stdout)); + } + }); + + for signal in signals.forever() { + match signal { + SIGUSR1 => sig_poweroff(), + SIGCHLD | + SIGALRM => sig_reap(), + SIGINT => sig_reboot(), + _ => unreachable!(), + } + } +}