split arg processing with some before void
This commit is contained in:
parent
ed6827b74e
commit
398c604850
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 log::{debug, error, info};
|
||||||
|
|
||||||
use super::specification::{
|
mod args;
|
||||||
Arg, Entrypoint, Environment, FileSocket, Pipe, Specification, Trigger,
|
|
||||||
};
|
use args::PreparedArgs;
|
||||||
use super::{PipePair, SocketPair};
|
|
||||||
|
use crate::specification::{Entrypoint, Environment, Specification, Trigger};
|
||||||
use crate::void::VoidBuilder;
|
use crate::void::VoidBuilder;
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
|
use crate::{PipePair, SocketPair};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::net::TcpListener;
|
|
||||||
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
|
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
@ -60,16 +61,18 @@ impl<'a> Spawner<'a> {
|
|||||||
|
|
||||||
match &entrypoint.trigger {
|
match &entrypoint.trigger {
|
||||||
Trigger::Startup => {
|
Trigger::Startup => {
|
||||||
let binary = PathBuf::from(self.binary).canonicalize()?;
|
|
||||||
|
|
||||||
let mut builder = VoidBuilder::new();
|
let mut builder = VoidBuilder::new();
|
||||||
|
|
||||||
|
let binary = PathBuf::from(self.binary).canonicalize()?;
|
||||||
builder.mount(binary, "/entrypoint");
|
builder.mount(binary, "/entrypoint");
|
||||||
|
|
||||||
self.prepare_env(&mut builder, &entrypoint.environment);
|
self.prepare_env(&mut builder, &entrypoint.environment);
|
||||||
|
|
||||||
|
let args = PreparedArgs::prepare_ambient(&entrypoint.args)?;
|
||||||
|
|
||||||
let closure = || {
|
let closure = || {
|
||||||
let args = self
|
let args = args
|
||||||
.prepare_args(name, &entrypoint.args, &mut TriggerData::None)
|
.prepare_void_mut(self, name, &mut TriggerData::None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
if let Err(e) = unistd::execv(&CString::new("/entrypoint").unwrap(), &args)
|
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 closure =
|
||||||
|| {
|
|| {
|
||||||
let pipe_trigger = std::str::from_utf8(&buf[0..read_bytes]).unwrap();
|
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();
|
.unwrap();
|
||||||
|
|
||||||
if let Err(e) = unistd::execv(&CString::new("/entrypoint").unwrap(), &args)
|
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 closure = || {
|
||||||
let args = self
|
let args = args
|
||||||
.prepare_args_ref(
|
.prepare_void(self, name, &mut TriggerData::FileSocket(fds))
|
||||||
name,
|
|
||||||
&spec.args,
|
|
||||||
&mut TriggerData::FileSocket(fds),
|
|
||||||
)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
if let Err(e) =
|
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 {
|
pub enum Pipe {
|
||||||
Rx(String),
|
Rx(String),
|
||||||
Tx(String),
|
Tx(String),
|
||||||
@ -93,7 +93,7 @@ impl Pipe {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
|
||||||
pub enum FileSocket {
|
pub enum FileSocket {
|
||||||
Rx(String),
|
Rx(String),
|
||||||
Tx(String),
|
Tx(String),
|
||||||
|
Loading…
Reference in New Issue
Block a user