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 result;
|
||||||
mod system;
|
mod system;
|
||||||
mod platform;
|
|
||||||
|
|
||||||
use result::Result;
|
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<()> {
|
fn init() -> Result<()> {
|
||||||
platform::init()?;
|
let config = config::get_config()?;
|
||||||
println!("Hello, world!");
|
|
||||||
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{system::{self, Mount, MountType}, result::Result};
|
use crate::{system::{self, Mount, MountType}, result::Result};
|
||||||
|
|
||||||
trait Platform {
|
pub trait Platform {
|
||||||
/// Whether the current Platform is the `Self` platform.
|
/// Whether the current Platform is the `Self` platform.
|
||||||
///
|
///
|
||||||
/// This method should check for the existence of hardware devices that irrefutably defines
|
/// 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")]
|
#[cfg(feature = "aws")]
|
||||||
mod 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")]
|
#[cfg(feature = "aws")]
|
||||||
if aws::Aws.is()? {
|
if aws::Aws.is()? {
|
||||||
return Ok(Some(Box::new(aws::Aws)))
|
return Ok(Some(Box::new(aws::Aws)))
|
||||||
|
@ -70,18 +79,15 @@ fn get_current_platform() -> Result<Option<Box<dyn Platform>>> {
|
||||||
Ok(None)
|
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
|
// Error handling strategy: If a platform is compiled in and loaded, if platform
|
||||||
// specific error handling doesn't work, fall back to generic.
|
// specific error handling doesn't work, fall back to generic.
|
||||||
|
|
||||||
let platform = get_current_platform()?;
|
// NOTE: We need to make get_mounts _additional_ beyond a base set.
|
||||||
if let Some(platform) = platform {
|
// We need `/dev/nsm` to exist so Aws.is() works.
|
||||||
// NOTE: We need to make get_mounts _additional_ beyond a base set.
|
platform.get_mounts().and_then(init_filesystems)?;
|
||||||
// We need `/dev/nsm` to exist so Aws.is() works.
|
platform.get_modules().and_then(init_modules)?;
|
||||||
platform.get_mounts().and_then(init_filesystems)?;
|
platform.init()?;
|
||||||
platform.get_modules().and_then(init_modules)?;
|
|
||||||
platform.init()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use crate::result::{ctx_os_error, Context, Result};
|
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::{
|
use std::{
|
||||||
ffi::CString,
|
ffi::CString,
|
||||||
os::fd::{AsRawFd, RawFd},
|
os::fd::{AsRawFd, RawFd},
|
||||||
|
@ -165,3 +165,39 @@ pub fn close(fd: RawFd) -> Result<()> {
|
||||||
n => unreachable!("close({fd}) returned bad value: {n}"),
|
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