add process handling mechanisms
This commit is contained in:
parent
ac43f98cf6
commit
d9b4c98c1b
|
@ -0,0 +1,43 @@
|
|||
use crate::platform::{self, Platform};
|
||||
use crate::result::{Context, Result};
|
||||
|
||||
pub enum Mode {
|
||||
Spawn,
|
||||
Exec,
|
||||
}
|
||||
|
||||
pub struct Config {
|
||||
pub platform: Option<Box<dyn Platform>>,
|
||||
pub mode: Mode,
|
||||
pub target: String,
|
||||
}
|
||||
|
||||
pub fn get_config() -> Result<Config> {
|
||||
let mut values = std::collections::HashMap::<&str, String>::new();
|
||||
let cmdline = std::fs::read_to_string("/proc/cmdline")
|
||||
.context(format_args!("could not read kernel cmdline"))?;
|
||||
|
||||
for word in cmdline.split_whitespace() {
|
||||
if let Some((lhs, rhs)) = word.split_once('=') {
|
||||
if let Some(("nit", name)) = lhs.split_once('.') {
|
||||
values.insert(name, rhs.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mode = if let Some(mode) = values.remove("mode") {
|
||||
match &*mode {
|
||||
"spawn" => Mode::Spawn,
|
||||
"exec" => Mode::Exec,
|
||||
m => panic!("Bad mode: {m}"),
|
||||
}
|
||||
} else {
|
||||
Mode::Spawn
|
||||
};
|
||||
|
||||
let platform = platform::get_current_platform(values.remove("platform").as_deref())?;
|
||||
|
||||
let target = values.remove("target").unwrap();
|
||||
|
||||
Ok(Config { platform, mode, target })
|
||||
}
|
36
src/main.rs
36
src/main.rs
|
@ -1,6 +1,7 @@
|
|||
mod config;
|
||||
mod platform;
|
||||
mod result;
|
||||
mod system;
|
||||
mod platform;
|
||||
|
||||
use result::Result;
|
||||
|
||||
|
@ -15,9 +16,38 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
extern "C" fn handle_sigchld(_sig: i32) {
|
||||
// wait on all dead processes
|
||||
while system::syscall::waitpid(-1, libc::WNOHANG).is_ok() {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
|
||||
fn init() -> Result<()> {
|
||||
platform::init()?;
|
||||
println!("Hello, world!");
|
||||
let config = config::get_config()?;
|
||||
|
||||
if let Some(platform) = config.platform.as_deref() {
|
||||
platform::init(platform)?;
|
||||
} else if let Some(platform) = platform::get_current_platform(None)?.as_deref() {
|
||||
platform::init(platform)?;
|
||||
}
|
||||
|
||||
let command = &config.target;
|
||||
match config.mode {
|
||||
config::Mode::Spawn => {
|
||||
// set up a process reaper. any time a child process dies, a SIGCHLD will be fired, and
|
||||
// the signal handler will reap the processes
|
||||
system::syscall::signal(libc::SIGCHLD, handle_sigchld)?;
|
||||
loop {
|
||||
if let Err(e) = std::process::Command::new(command).spawn() {
|
||||
eprintln!("Encountered error running {command}: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
config::Mode::Exec => {
|
||||
system::syscall::execv(command, &[])?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{system::{self, Mount, MountType}, result::Result};
|
||||
|
||||
trait Platform {
|
||||
pub trait Platform {
|
||||
/// Whether the current Platform is the `Self` platform.
|
||||
///
|
||||
/// This method should check for the existence of hardware devices that irrefutably defines
|
||||
|
@ -61,7 +61,16 @@ fn init_modules(iter: impl IntoIterator<Item = (String, String)>) -> Result<()>
|
|||
#[cfg(feature = "aws")]
|
||||
mod aws;
|
||||
|
||||
fn get_current_platform() -> Result<Option<Box<dyn Platform>>> {
|
||||
pub fn get_current_platform(name: Option<&str>) -> Result<Option<Box<dyn Platform>>> {
|
||||
#[allow(clippy::collapsible_match)]
|
||||
if let Some(name) = name {
|
||||
match name {
|
||||
#[cfg(feature = "aws")]
|
||||
"aws" => return Ok(Some(Box::new(aws::Aws))),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "aws")]
|
||||
if aws::Aws.is()? {
|
||||
return Ok(Some(Box::new(aws::Aws)))
|
||||
|
@ -70,18 +79,15 @@ fn get_current_platform() -> Result<Option<Box<dyn Platform>>> {
|
|||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn init() -> Result<()> {
|
||||
pub fn init(platform: &dyn Platform) -> Result<()> {
|
||||
// Error handling strategy: If a platform is compiled in and loaded, if platform
|
||||
// specific error handling doesn't work, fall back to generic.
|
||||
|
||||
let platform = get_current_platform()?;
|
||||
if let Some(platform) = platform {
|
||||
// NOTE: We need to make get_mounts _additional_ beyond a base set.
|
||||
// We need `/dev/nsm` to exist so Aws.is() works.
|
||||
platform.get_mounts().and_then(init_filesystems)?;
|
||||
platform.get_modules().and_then(init_modules)?;
|
||||
platform.init()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use crate::result::{ctx_os_error, Context, Result};
|
||||
use libc::{self, c_ulong, c_void};
|
||||
use libc::{self, c_int, c_ulong, c_void};
|
||||
use std::{
|
||||
ffi::CString,
|
||||
os::fd::{AsRawFd, RawFd},
|
||||
|
@ -165,3 +165,39 @@ pub fn close(fd: RawFd) -> Result<()> {
|
|||
n => unreachable!("close({fd}) returned bad value: {n}"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execv(command: impl AsRef<Path>, args: &[&str]) -> Result<()> {
|
||||
let command = command.as_ref();
|
||||
|
||||
let command_cstr = CString::new(command.as_os_str().as_encoded_bytes())
|
||||
.context(format_args!("bad command: {}", command.display()))?;
|
||||
let mut args_cstr = vec![];
|
||||
for arg in args {
|
||||
let cur_arg_cstr = CString::new(arg.as_bytes()).context(format_args!("bad arg: {arg}"));
|
||||
args_cstr.push(cur_arg_cstr);
|
||||
}
|
||||
|
||||
if unsafe { libc::execv(command_cstr.as_ptr().cast(), args_cstr.as_ptr().cast()) } == -1 {
|
||||
return ctx_os_error(format_args!("error calling exec()"));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub type SignalHandler = extern "C" fn(c_int);
|
||||
|
||||
pub fn signal(signal: i32, handler: SignalHandler) -> Result<()> {
|
||||
#[allow(clippy::single_match)]
|
||||
match unsafe { libc::signal(signal as i32, handler as libc::sighandler_t) } {
|
||||
libc::SIG_ERR => ctx_os_error(format_args!("invalid handler for {signal:?}")),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn waitpid(pid: libc::pid_t, flags: i32) -> Result<libc::pid_t> {
|
||||
match unsafe { libc::waitpid(pid, std::ptr::null_mut(), flags) } {
|
||||
pid @ 0.. => Ok(pid),
|
||||
-1 => ctx_os_error(format_args!("error calling waitpid({pid}, {flags})")).map(|()| 0),
|
||||
n => unreachable!("waitpid({pid}, {flags}) returned bad value: {n}"),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue