adding runlevels & fixing unpredictable loading order

This commit is contained in:
darkgallium 2020-06-20 19:43:19 +02:00
parent 06b4d1bf10
commit 9e75ea95c8
2 changed files with 106 additions and 82 deletions

View File

@ -14,11 +14,38 @@ use nix::sys::signal::kill;
use nix::unistd::Pid; use nix::unistd::Pid;
use tokio; use tokio;
fn sigint_handler() { fn shutdown_handler() {
println!("Received signal SIGINT"); println!("stopping services");
process::exit(0); 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() { fn reap_handler() {
loop { loop {
match waitpid(Some(Pid::from_raw(-1)), Some(WaitPidFlag::WNOHANG)) { match waitpid(Some(Pid::from_raw(-1)), Some(WaitPidFlag::WNOHANG)) {
@ -50,77 +77,65 @@ fn set_hostname() {
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> { async fn main() -> Result<(), Box<dyn Error>> {
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 if process::id() == 1 {
processes::sync_run_wait("agetty", ["--noclear", "tty1"].as_ref()); 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"); println!("set hostname");
svc::stop_services(); set_hostname();
println!("killing remaining processes"); println!("mount all partitions");
let pids = processes::get_all_pids(); processes::run("mount", ["-a"].as_ref()).await;
processes::run("swapon", ["-a"].as_ref()).await;
for pid in pids { println!("load udev");
let res = kill(Pid::from_raw(pid), Signal::SIGKILL); processes::run("/usr/lib/systemd/systemd-udevd", ["-d"].as_ref()).await;
match res { processes::run("udevadm", ["trigger", "--action=add", "--type=subsystems"].as_ref()).await;
Ok(_) => {} processes::run("udevadm", ["trigger", "--action=add", "--type=devices"].as_ref()).await;
Err(err) => eprintln!("error killing process {}, error is {}", pid, err) 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(()) Ok(())
} }

View File

@ -1,5 +1,6 @@
use std::{fs, path::Path}; use std::{fs, path::Path};
use serde::Deserialize; use serde::Deserialize;
use std::collections::BTreeMap;
use toml; use toml;
use tokio; use tokio;
use crate::processes; use crate::processes;
@ -7,6 +8,7 @@ use crate::processes;
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct Service { pub struct Service {
pub name: String, pub name: String,
pub level: u16,
pub start: Start, pub start: Start,
pub stop: Option<Stop>, pub stop: Option<Stop>,
} }
@ -23,8 +25,9 @@ pub struct Stop {
pub args: Vec<String> pub args: Vec<String>
} }
pub fn get_services() -> Vec<Service> { pub fn get_services() -> BTreeMap<u16, Vec<Service>> {
let mut services = Vec::new(); let mut services = BTreeMap::new();
//let mut services = Vec::new();
let mini_dir = Path::new("/etc/mini/"); let mini_dir = Path::new("/etc/mini/");
if mini_dir.exists() && mini_dir.is_dir() { if mini_dir.exists() && mini_dir.is_dir() {
@ -35,7 +38,9 @@ pub fn get_services() -> Vec<Service> {
// TODO: check ext // TODO: check ext
let svc_file_contents = fs::read_to_string(file.unwrap().path()).unwrap(); let svc_file_contents = fs::read_to_string(file.unwrap().path()).unwrap();
let svc : Service = toml::from_str(&svc_file_contents).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<Service> {
pub async fn launch_services() { pub async fn launch_services() {
let services = get_services(); let services = get_services();
for s in services { for (level, svc_list) in services {
tokio::spawn(async move { for s in svc_list {
println!("starting {}", s.name); tokio::spawn(async move {
let args: Vec<&str> = s.start.args.iter().map(|e| e.as_str()).collect(); println!("starting {}[{}]", s.name, level);
processes::run(&s.start.command, &args[..]).await; 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() { pub fn stop_services() {
let services = get_services(); let services = get_services();
for s in services { for (level, svc_list) in services.iter().rev() {
println!("stopping {}", s.name); for s in svc_list {
if let Some(stop) = s.stop { println!("stopping {}[{}]", s.name, level);
let args: Vec<&str> = stop.args.iter().map(|e| e.as_str()).collect(); if let Some(stop) = &s.stop {
processes::sync_run_wait(&stop.command, &args[..]); let args: Vec<&str> = stop.args.iter().map(|e| e.as_str()).collect();
processes::sync_run_wait(&stop.command, &args[..]);
}
} }
} }
} }