split arg processing with some before void #19
176
src/spawner/args.rs
Normal file
176
src/spawner/args.rs
Normal file
@ -0,0 +1,176 @@
|
||||
use super::{Spawner, TriggerData};
|
||||
use crate::specification::{Arg, FileSocket, Pipe};
|
||||
use crate::{Error, Result};
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::fs::File;
|
||||
use std::net::TcpListener;
|
||||
use std::os::unix::io::IntoRawFd;
|
||||
|
||||
/**
|
||||
* perform initial processing with ambient authority
|
||||
* for things like network sockets.
|
||||
*/
|
||||
pub struct PreparedArgs(Vec<PreparedArg>);
|
||||
|
||||
impl PreparedArgs {
|
||||
pub fn prepare_ambient(args: &[Arg]) -> Result<Self> {
|
||||
let mut v = Vec::with_capacity(args.len());
|
||||
|
||||
for arg in args {
|
||||
v.push(PreparedArg::prepare_ambient(arg)?);
|
||||
}
|
||||
|
||||
Ok(PreparedArgs(v))
|
||||
}
|
||||
|
||||
pub(super) fn prepare_void_mut(
|
||||
self,
|
||||
spawner: &mut Spawner,
|
||||
entrypoint: &str,
|
||||
trigger: &mut TriggerData,
|
||||
) -> Result<Vec<CString>> {
|
||||
let mut v = Vec::new();
|
||||
|
||||
for arg in self.0 {
|
||||
v.extend(arg.prepare_void_mut(spawner, entrypoint, trigger)?)
|
||||
}
|
||||
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
pub(super) fn prepare_void(
|
||||
self,
|
||||
spawner: &Spawner,
|
||||
entrypoint: &str,
|
||||
trigger: &mut TriggerData,
|
||||
) -> Result<Vec<CString>> {
|
||||
let mut v = Vec::new();
|
||||
|
||||
for arg in self.0 {
|
||||
v.extend(arg.prepare_void(spawner, entrypoint, trigger)?)
|
||||
}
|
||||
|
||||
Ok(v)
|
||||
}
|
||||
}
|
||||
enum PreparedArg {
|
||||
/// The binary name, or argv[0], of the original program start
|
||||
BinaryName,
|
||||
|
||||
/// The name of this entrypoint
|
||||
Entrypoint,
|
||||
|
||||
/// A file descriptor for a file on the filesystem in the launching namespace
|
||||
File(File),
|
||||
|
||||
/// A chosen end of a named pipe
|
||||
Pipe(Pipe),
|
||||
|
||||
/// File socket
|
||||
FileSocket(FileSocket),
|
||||
|
||||
/// A value specified by the trigger
|
||||
/// NOTE: Only valid if the trigger is of type Pipe(...) or FileSocket(...)
|
||||
Trigger,
|
||||
|
||||
/// A TCP Listener
|
||||
TcpListener { socket: TcpListener },
|
||||
|
||||
/// The rest of argv[1..], 0 or more arguments
|
||||
Trailing,
|
||||
}
|
||||
|
||||
impl PreparedArg {
|
||||
/**
|
||||
* Process the parts of the argument which must be processed
|
||||
* with ambient authority
|
||||
*
|
||||
* Leave the remainder untouched so they can be processed in parallel
|
||||
* (in the child process) and to reduce authority
|
||||
*/
|
||||
fn prepare_ambient(arg: &Arg) -> Result<Self> {
|
||||
Ok(match arg {
|
||||
Arg::File(path) => PreparedArg::File(File::open(path)?),
|
||||
|
||||
Arg::TcpListener { addr } => PreparedArg::TcpListener {
|
||||
socket: TcpListener::bind(addr)?,
|
||||
},
|
||||
|
||||
Arg::BinaryName => PreparedArg::BinaryName,
|
||||
Arg::Entrypoint => PreparedArg::Entrypoint,
|
||||
Arg::Pipe(p) => PreparedArg::Pipe(p.clone()),
|
||||
Arg::FileSocket(s) => PreparedArg::FileSocket(s.clone()),
|
||||
Arg::Trigger => PreparedArg::Trigger,
|
||||
Arg::Trailing => PreparedArg::Trailing,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete argument preparation in the void
|
||||
*/
|
||||
fn prepare_void_mut(
|
||||
self,
|
||||
spawner: &mut Spawner,
|
||||
entrypoint: &str,
|
||||
trigger: &mut TriggerData,
|
||||
) -> Result<Vec<CString>> {
|
||||
match self {
|
||||
PreparedArg::Pipe(p) => match p {
|
||||
Pipe::Rx(s) => {
|
||||
let pipe = spawner.pipes.get_mut(&s).unwrap().take_read()?;
|
||||
Ok(vec![CString::new(pipe.into_raw_fd().to_string()).unwrap()])
|
||||
}
|
||||
Pipe::Tx(s) => {
|
||||
let pipe = spawner.pipes.get_mut(&s).unwrap().take_write()?;
|
||||
Ok(vec![CString::new(pipe.into_raw_fd().to_string()).unwrap()])
|
||||
}
|
||||
},
|
||||
|
||||
PreparedArg::FileSocket(s) => match s {
|
||||
FileSocket::Rx(s) => {
|
||||
let pipe = spawner.sockets.get_mut(&s).unwrap().take_read()?;
|
||||
Ok(vec![CString::new(pipe.into_raw_fd().to_string()).unwrap()])
|
||||
}
|
||||
FileSocket::Tx(s) => {
|
||||
let pipe = spawner.sockets.get_mut(&s).unwrap().take_write()?;
|
||||
Ok(vec![CString::new(pipe.into_raw_fd().to_string()).unwrap()])
|
||||
}
|
||||
},
|
||||
|
||||
arg => arg.prepare_void(spawner, entrypoint, trigger),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete argument preparation in the void
|
||||
*/
|
||||
fn prepare_void(
|
||||
self,
|
||||
spawner: &Spawner,
|
||||
entrypoint: &str,
|
||||
trigger: &mut TriggerData,
|
||||
) -> Result<Vec<CString>> {
|
||||
match self {
|
||||
PreparedArg::BinaryName => Ok(vec![CString::new(spawner.binary).unwrap()]),
|
||||
PreparedArg::Entrypoint => Ok(vec![CString::new(entrypoint).unwrap()]),
|
||||
|
||||
PreparedArg::Pipe(p) => Err(Error::BadPipe(p.get_name().to_string())),
|
||||
PreparedArg::FileSocket(s) => Err(Error::BadFileSocket(s.get_name().to_string())),
|
||||
|
||||
PreparedArg::File(f) => Ok(vec![CString::new(f.into_raw_fd().to_string()).unwrap()]),
|
||||
|
||||
PreparedArg::Trigger => Ok(trigger.args()),
|
||||
|
||||
PreparedArg::TcpListener { socket } => {
|
||||
Ok(vec![CString::new(socket.into_raw_fd().to_string()).unwrap()])
|
||||
}
|
||||
|
||||
PreparedArg::Trailing => Ok(spawner
|
||||
.trailing
|
||||
.iter()
|
||||
.map(|s| CString::new(*s).unwrap())
|
||||
.collect()),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +1,18 @@
|
||||
use log::{debug, error, info};
|
||||
|
||||
use super::specification::{
|
||||
Arg, Entrypoint, Environment, FileSocket, Pipe, Specification, Trigger,
|
||||
};
|
||||
use super::{PipePair, SocketPair};
|
||||
mod args;
|
||||
|
||||
use args::PreparedArgs;
|
||||
|
||||
use crate::specification::{Entrypoint, Environment, Specification, Trigger};
|
||||
use crate::void::VoidBuilder;
|
||||
use crate::{Error, Result};
|
||||
use crate::{PipePair, SocketPair};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::CString;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::net::TcpListener;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
|
||||
use std::path::PathBuf;
|
||||
|
||||
@ -60,16 +61,18 @@ impl<'a> Spawner<'a> {
|
||||
|
||||
match &entrypoint.trigger {
|
||||
Trigger::Startup => {
|
||||
let binary = PathBuf::from(self.binary).canonicalize()?;
|
||||
|
||||
let mut builder = VoidBuilder::new();
|
||||
|
||||
let binary = PathBuf::from(self.binary).canonicalize()?;
|
||||
builder.mount(binary, "/entrypoint");
|
||||
|
||||
self.prepare_env(&mut builder, &entrypoint.environment);
|
||||
|
||||
let args = PreparedArgs::prepare_ambient(&entrypoint.args)?;
|
||||
|
||||
let closure = || {
|
||||
let args = self
|
||||
.prepare_args(name, &entrypoint.args, &mut TriggerData::None)
|
||||
let args = args
|
||||
.prepare_void_mut(self, name, &mut TriggerData::None)
|
||||
.unwrap();
|
||||
|
||||
if let Err(e) = unistd::execv(&CString::new("/entrypoint").unwrap(), &args)
|
||||
@ -159,11 +162,14 @@ impl<'a> Spawner<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
let args = PreparedArgs::prepare_ambient(&spec.args)?;
|
||||
|
||||
let closure =
|
||||
|| {
|
||||
let pipe_trigger = std::str::from_utf8(&buf[0..read_bytes]).unwrap();
|
||||
let args = self
|
||||
.prepare_args_ref(name, &spec.args, &mut TriggerData::Pipe(pipe_trigger))
|
||||
|
||||
let args = args
|
||||
.prepare_void(self, name, &mut TriggerData::Pipe(pipe_trigger))
|
||||
.unwrap();
|
||||
|
||||
if let Err(e) = unistd::execv(&CString::new("/entrypoint").unwrap(), &args)
|
||||
@ -220,13 +226,11 @@ impl<'a> Spawner<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
let args = PreparedArgs::prepare_ambient(&spec.args)?;
|
||||
|
||||
let closure = || {
|
||||
let args = self
|
||||
.prepare_args_ref(
|
||||
name,
|
||||
&spec.args,
|
||||
&mut TriggerData::FileSocket(fds),
|
||||
)
|
||||
let args = args
|
||||
.prepare_void(self, name, &mut TriggerData::FileSocket(fds))
|
||||
.unwrap();
|
||||
|
||||
if let Err(e) =
|
||||
@ -268,100 +272,4 @@ impl<'a> Spawner<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare_args(
|
||||
&mut self,
|
||||
entrypoint: &str,
|
||||
args: &[Arg],
|
||||
trigger: &mut TriggerData,
|
||||
) -> Result<Vec<CString>> {
|
||||
let mut out = Vec::new();
|
||||
for arg in args {
|
||||
out.extend(self.prepare_arg(entrypoint, arg, trigger)?);
|
||||
}
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
fn prepare_args_ref(
|
||||
&self,
|
||||
entrypoint: &str,
|
||||
args: &[Arg],
|
||||
trigger: &mut TriggerData,
|
||||
) -> Result<Vec<CString>> {
|
||||
let mut out = Vec::new();
|
||||
for arg in args {
|
||||
out.extend(self.prepare_arg_ref(entrypoint, arg, trigger)?);
|
||||
}
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
fn prepare_arg(
|
||||
&mut self,
|
||||
entrypoint: &str,
|
||||
arg: &Arg,
|
||||
trigger: &mut TriggerData,
|
||||
) -> Result<Vec<CString>> {
|
||||
match arg {
|
||||
Arg::Pipe(p) => match p {
|
||||
Pipe::Rx(s) => {
|
||||
let pipe = self.pipes.get_mut(s).unwrap().take_read()?;
|
||||
Ok(vec![CString::new(pipe.into_raw_fd().to_string()).unwrap()])
|
||||
}
|
||||
Pipe::Tx(s) => {
|
||||
let pipe = self.pipes.get_mut(s).unwrap().take_write()?;
|
||||
Ok(vec![CString::new(pipe.into_raw_fd().to_string()).unwrap()])
|
||||
}
|
||||
},
|
||||
|
||||
Arg::FileSocket(s) => match s {
|
||||
FileSocket::Rx(s) => {
|
||||
let pipe = self.sockets.get_mut(s).unwrap().take_read()?;
|
||||
Ok(vec![CString::new(pipe.into_raw_fd().to_string()).unwrap()])
|
||||
}
|
||||
FileSocket::Tx(s) => {
|
||||
let pipe = self.sockets.get_mut(s).unwrap().take_write()?;
|
||||
Ok(vec![CString::new(pipe.into_raw_fd().to_string()).unwrap()])
|
||||
}
|
||||
},
|
||||
|
||||
a => self.prepare_arg_ref(entrypoint, a, trigger),
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare_arg_ref(
|
||||
&self,
|
||||
entrypoint: &str,
|
||||
arg: &Arg,
|
||||
trigger: &mut TriggerData,
|
||||
) -> Result<Vec<CString>> {
|
||||
match arg {
|
||||
Arg::BinaryName => Ok(vec![CString::new(self.binary).unwrap()]),
|
||||
Arg::Entrypoint => Ok(vec![CString::new(entrypoint).unwrap()]),
|
||||
|
||||
Arg::Pipe(p) => Err(Error::BadPipe(p.get_name().to_string())),
|
||||
Arg::FileSocket(s) => Err(Error::BadFileSocket(s.get_name().to_string())),
|
||||
|
||||
Arg::File(p) => {
|
||||
let f = File::open(p)?.into_raw_fd();
|
||||
Ok(vec![CString::new(f.to_string()).unwrap()])
|
||||
}
|
||||
|
||||
Arg::Trigger => Ok(trigger.args()),
|
||||
|
||||
Arg::TcpListener { addr } => {
|
||||
let listener = TcpListener::bind(addr)?;
|
||||
let listener = listener.into_raw_fd();
|
||||
|
||||
Ok(vec![CString::new(listener.to_string()).unwrap()])
|
||||
}
|
||||
|
||||
Arg::Trailing => Ok(self
|
||||
.trailing
|
||||
.iter()
|
||||
.map(|s| CString::new(*s).unwrap())
|
||||
.collect()),
|
||||
}
|
||||
}
|
||||
}
|
@ -78,7 +78,7 @@ impl Arg {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
|
||||
pub enum Pipe {
|
||||
Rx(String),
|
||||
Tx(String),
|
||||
@ -93,7 +93,7 @@ impl Pipe {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
|
||||
pub enum FileSocket {
|
||||
Rx(String),
|
||||
Tx(String),
|
||||
|
Loading…
Reference in New Issue
Block a user