From 9e75ea95c82247eedd0cbfa63e07c4898f8eb6b9 Mon Sep 17 00:00:00 2001 From: darkgallium Date: Sat, 20 Jun 2020 19:43:19 +0200 Subject: [PATCH] adding runlevels & fixing unpredictable loading order --- src/main.rs | 151 +++++++++++++++++++++++++++++----------------------- src/svc.rs | 37 ++++++++----- 2 files changed, 106 insertions(+), 82 deletions(-) diff --git a/src/main.rs b/src/main.rs index 152c4b0..b0c0ff0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,11 +14,38 @@ use nix::sys::signal::kill; use nix::unistd::Pid; use tokio; -fn sigint_handler() { - println!("Received signal SIGINT"); - process::exit(0); +fn shutdown_handler() { + println!("stopping services"); + svc::stop_services(); + + println!("killing remaining processes"); + let pids = processes::get_all_pids(); + + for pid in pids { + let res = kill(Pid::from_raw(pid), Signal::SIGKILL); + match res { + Ok(_) => {} + Err(err) => eprintln!("error killing process {}, error is {}", pid, err) + } + } + + println!("unmounting all partitions"); + processes::sync_run_wait("swapoff", ["-a"].as_ref()); + processes::sync_run_wait("umount", ["-a", "-f"].as_ref()); + + println!("syncing disks"); + processes::sync_run_wait("sync", [].as_ref()); + + println!("end pre-shutdown routines"); + + #[allow(unused_must_use)] { + reboot(RebootMode::RB_POWER_OFF); + } + } + + fn reap_handler() { loop { match waitpid(Some(Pid::from_raw(-1)), Some(WaitPidFlag::WNOHANG)) { @@ -50,77 +77,65 @@ fn set_hostname() { #[tokio::main] async fn main() -> Result<(), Box> { - - - println!("mini, the bare minimum init by darkgallium"); - println!(); - - println!("remount /"); - processes::run("mount", ["-o", "remount", "/"].as_ref()).await; - - println!("set hostname"); - set_hostname(); - - println!("mount all partitions"); - processes::run("mount", ["-a"].as_ref()).await; - processes::run("swapon", ["-a"].as_ref()).await; - - println!("load udev"); - processes::run("/usr/lib/systemd/systemd-udevd", ["-d"].as_ref()).await; - processes::run("udevadm", ["trigger", "--action=add", "--type=subsystems"].as_ref()).await; - processes::run("udevadm", ["trigger", "--action=add", "--type=devices"].as_ref()).await; - processes::run("udevadm", ["settle"].as_ref()).await; - - // misc stuff in another thread - tokio::spawn(async { - println!("setting keymap"); - processes::run("loadkeys", ["fr-latin9"].as_ref()).await; - - println!("mounting pty"); - processes::run("mkdir", ["/dev/pts"].as_ref()).await; - processes::run("mount", ["devpts", "/dev/pts", "-t", "devpts"].as_ref()).await; - }); - - println!("load dbus"); - processes::run("mkdir", ["/run/dbus"].as_ref()).await; - processes::run("dbus-daemon", ["--system"].as_ref()).await; // a lot of services depend on dbus being on - - println!("now loading your services"); - svc::launch_services().await; - - unsafe { signal_hook::register(SIGINT, sigint_handler) }?; - let sigchld_handle = unsafe { signal_hook::register(SIGCHLD, reap_handler) }?; - - println!("end bootstrap, launching your terminals"); - // TODO: spawn a thread by tty and join threads at end - processes::sync_run_wait("agetty", ["--noclear", "tty1"].as_ref()); + if process::id() == 1 { + println!("mini, the bare minimum init by darkgallium"); + println!(); - signal_hook::unregister(sigchld_handle); + println!("remount /"); + processes::run("mount", ["-o", "remount", "/"].as_ref()).await; - println!("stopping services"); - svc::stop_services(); + println!("set hostname"); + set_hostname(); - println!("killing remaining processes"); - let pids = processes::get_all_pids(); + println!("mount all partitions"); + processes::run("mount", ["-a"].as_ref()).await; + processes::run("swapon", ["-a"].as_ref()).await; - for pid in pids { - let res = kill(Pid::from_raw(pid), Signal::SIGKILL); - match res { - Ok(_) => {} - Err(err) => eprintln!("error killing process {}, error is {}", pid, err) - } + println!("load udev"); + processes::run("/usr/lib/systemd/systemd-udevd", ["-d"].as_ref()).await; + processes::run("udevadm", ["trigger", "--action=add", "--type=subsystems"].as_ref()).await; + processes::run("udevadm", ["trigger", "--action=add", "--type=devices"].as_ref()).await; + processes::run("udevadm", ["settle"].as_ref()).await; + + // misc stuff in another thread + tokio::spawn(async { + println!("setting keymap"); + processes::run("loadkeys", ["fr-latin9"].as_ref()).await; + + println!("mounting pty"); + processes::run("mkdir", ["/dev/pts"].as_ref()).await; + processes::run("mount", ["devpts", "/dev/pts", "-t", "devpts"].as_ref()).await; + }); + + println!("load dbus"); + processes::run("mkdir", ["/run/dbus"].as_ref()).await; + processes::run("dbus-daemon", ["--system"].as_ref()).await; // a lot of services depend on dbus being on + + let sigchld_handle = unsafe { signal_hook::register(SIGCHLD, reap_handler) }?; + let sigchld_handle_c = sigchld_handle.clone(); + + unsafe { signal_hook::register(SIGINT, move || { + signal_hook::unregister(sigchld_handle); + shutdown_handler(); + }) }?; + + + println!("loading services"); + svc::launch_services().await; + + println!("end bootstrap, launching your terminals"); + + tokio::spawn(async { + processes::run("agetty", ["--noclear", "tty1"].as_ref()).await; + }).await; + + signal_hook::unregister(sigchld_handle_c); + shutdown_handler(); + + } else { + } - println!("unmounting all partitions"); - processes::run("swapoff", ["-a"].as_ref()).await; - processes::run("umount", ["-a", "-f"].as_ref()).await; - - println!("end pre-shutdown routines"); - - #[allow(unused_must_use)] { - reboot(RebootMode::RB_POWER_OFF); - } - Ok(()) } diff --git a/src/svc.rs b/src/svc.rs index b517d23..4c692f9 100644 --- a/src/svc.rs +++ b/src/svc.rs @@ -1,5 +1,6 @@ use std::{fs, path::Path}; use serde::Deserialize; +use std::collections::BTreeMap; use toml; use tokio; use crate::processes; @@ -7,6 +8,7 @@ use crate::processes; #[derive(Deserialize, Debug)] pub struct Service { pub name: String, + pub level: u16, pub start: Start, pub stop: Option, } @@ -23,8 +25,9 @@ pub struct Stop { pub args: Vec } -pub fn get_services() -> Vec { - let mut services = Vec::new(); +pub fn get_services() -> BTreeMap> { + let mut services = BTreeMap::new(); + //let mut services = Vec::new(); let mini_dir = Path::new("/etc/mini/"); if mini_dir.exists() && mini_dir.is_dir() { @@ -35,7 +38,9 @@ pub fn get_services() -> Vec { // TODO: check ext let svc_file_contents = fs::read_to_string(file.unwrap().path()).unwrap(); let svc : Service = toml::from_str(&svc_file_contents).unwrap(); - services.push(svc); + + let lvl = services.entry(svc.level).or_insert(Vec::new()); + lvl.push(svc); } } @@ -46,23 +51,27 @@ pub fn get_services() -> Vec { pub async fn launch_services() { let services = get_services(); - for s in services { - tokio::spawn(async move { - println!("starting {}", s.name); - let args: Vec<&str> = s.start.args.iter().map(|e| e.as_str()).collect(); - processes::run(&s.start.command, &args[..]).await; - }); + for (level, svc_list) in services { + for s in svc_list { + tokio::spawn(async move { + println!("starting {}[{}]", s.name, level); + let args: Vec<&str> = s.start.args.iter().map(|e| e.as_str()).collect(); + processes::run(&s.start.command, &args[..]).await; + }); + } } } pub fn stop_services() { let services = get_services(); - for s in services { - println!("stopping {}", s.name); - if let Some(stop) = s.stop { - let args: Vec<&str> = stop.args.iter().map(|e| e.as_str()).collect(); - processes::sync_run_wait(&stop.command, &args[..]); + for (level, svc_list) in services.iter().rev() { + for s in svc_list { + println!("stopping {}[{}]", s.name, level); + if let Some(stop) = &s.stop { + let args: Vec<&str> = stop.args.iter().map(|e| e.as_str()).collect(); + processes::sync_run_wait(&stop.command, &args[..]); + } } } }