Add coordinator-owned interactive session terminals
This commit is contained in:
parent
3b76b59bdf
commit
51ff63a3aa
1 changed files with 2078 additions and 15 deletions
|
|
@ -31,6 +31,7 @@ pub struct TargetCommand {
|
|||
arguments: Vec<OsString>,
|
||||
parent_edge: ParentEdge,
|
||||
executable: Option<OwnedFd>,
|
||||
stdin: Option<File>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
|
|
@ -47,6 +48,7 @@ impl TargetCommand {
|
|||
arguments: Vec::new(),
|
||||
parent_edge: ParentEdge::ParentDeathKill,
|
||||
executable: None,
|
||||
stdin: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -64,6 +66,7 @@ impl TargetCommand {
|
|||
arguments: arguments.into_iter().collect(),
|
||||
parent_edge: ParentEdge::ParentDeathKill,
|
||||
executable: Some(executable),
|
||||
stdin: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -85,6 +88,16 @@ impl TargetCommand {
|
|||
self
|
||||
}
|
||||
|
||||
/// Attaches the target's standard input after the private wrapper consumes its barrier.
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns an error when the descriptor cannot be inherited by the wrapper.
|
||||
pub fn with_target_stdin(mut self, stdin: File) -> io::Result<Self> {
|
||||
fcntl_setfd(stdin.as_fd(), FdFlags::empty())?;
|
||||
self.stdin = Some(stdin);
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn parent_edge(&self) -> ParentEdge {
|
||||
self.parent_edge
|
||||
|
|
@ -109,6 +122,18 @@ impl TargetCommand {
|
|||
ParentEdge::ParentDeathKill => "kill",
|
||||
ParentEdge::LifetimePipe => "lifetime-pipe",
|
||||
})
|
||||
.args(
|
||||
self.stdin
|
||||
.as_ref()
|
||||
.map(|stdin| {
|
||||
[
|
||||
OsString::from("--target-stdin-fd"),
|
||||
OsString::from(stdin.as_raw_fd().to_string()),
|
||||
]
|
||||
})
|
||||
.into_iter()
|
||||
.flatten(),
|
||||
)
|
||||
.arg("--")
|
||||
.arg(&self.program)
|
||||
.args(&self.arguments);
|
||||
|
|
@ -126,6 +151,7 @@ pub enum ChildStandardIoPolicy {
|
|||
Inherit,
|
||||
PrivateControlWithLifetimePipe,
|
||||
Silenced,
|
||||
Terminal,
|
||||
}
|
||||
|
||||
impl ChildStandardIo {
|
||||
|
|
@ -159,6 +185,17 @@ impl ChildStandardIo {
|
|||
}
|
||||
}
|
||||
|
||||
/// # Errors
|
||||
/// Returns an error when the output descriptor cannot be duplicated for merged terminal I/O.
|
||||
pub fn terminal(output: File) -> io::Result<Self> {
|
||||
let error = output.try_clone()?;
|
||||
Ok(Self {
|
||||
stdout: Some(Stdio::from(output)),
|
||||
stderr: Some(Stdio::from(error)),
|
||||
policy: ChildStandardIoPolicy::Terminal,
|
||||
})
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn policy(&self) -> ChildStandardIoPolicy {
|
||||
self.policy
|
||||
|
|
@ -296,7 +333,9 @@ fn require_parent_edge_standard_io(
|
|||
(ParentEdge::LifetimePipe, ChildStandardIoPolicy::PrivateControlWithLifetimePipe)
|
||||
| (
|
||||
ParentEdge::ParentDeathKill,
|
||||
ChildStandardIoPolicy::Inherit | ChildStandardIoPolicy::Silenced,
|
||||
ChildStandardIoPolicy::Inherit
|
||||
| ChildStandardIoPolicy::Silenced
|
||||
| ChildStandardIoPolicy::Terminal,
|
||||
) => Ok(()),
|
||||
(ParentEdge::LifetimePipe, _) => Err(io::Error::other(
|
||||
"lifetime-pipe parent edge requires private control stdout and lifetime-pipe stderr",
|
||||
|
|
@ -778,6 +817,9 @@ fn run_wrapper_role(arguments: Vec<OsString>) -> io::Result<()> {
|
|||
require_lifetime_pipe_and_recheck(expected_parent)?;
|
||||
}
|
||||
}
|
||||
if let Some(stdin) = target.stdin.as_ref() {
|
||||
rustix::stdio::dup2_stdin(stdin)?;
|
||||
}
|
||||
Err(exec_target(target))
|
||||
}
|
||||
|
||||
|
|
@ -1245,9 +1287,22 @@ pub fn parse_wrapper_arguments(
|
|||
Some("lifetime-pipe") => ParentEdge::LifetimePipe,
|
||||
_ => return Err(io::Error::other("wrapper parent action is invalid")),
|
||||
};
|
||||
if arguments.next().as_deref() != Some(OsStr::new("--")) {
|
||||
let next = arguments.next();
|
||||
let stdin = if next.as_deref() == Some(OsStr::new("--target-stdin-fd")) {
|
||||
let descriptor = arguments
|
||||
.next()
|
||||
.and_then(|value| value.to_str().and_then(|value| value.parse::<i32>().ok()))
|
||||
.filter(|descriptor| *descriptor > 2)
|
||||
.ok_or_else(|| io::Error::other("wrapper target stdin descriptor is invalid"))?;
|
||||
if arguments.next().as_deref() != Some(OsStr::new("--")) {
|
||||
return Err(io::Error::other("wrapper target separator is missing"));
|
||||
}
|
||||
Some(File::open(format!("/proc/self/fd/{descriptor}"))?)
|
||||
} else if next.as_deref() == Some(OsStr::new("--")) {
|
||||
None
|
||||
} else {
|
||||
return Err(io::Error::other("wrapper target separator is missing"));
|
||||
}
|
||||
};
|
||||
let program = arguments
|
||||
.next()
|
||||
.ok_or_else(|| io::Error::other("wrapper target is missing"))?;
|
||||
|
|
@ -1256,6 +1311,7 @@ pub fn parse_wrapper_arguments(
|
|||
arguments: arguments.collect(),
|
||||
parent_edge,
|
||||
executable: None,
|
||||
stdin,
|
||||
};
|
||||
let boot = parse_boot_hex(&boot)?;
|
||||
Ok((
|
||||
|
|
|
|||
Loading…
Reference in a new issue