Preserve inherited target stdin authority
This commit is contained in:
parent
39307f4281
commit
f5455d1d6c
1 changed files with 109 additions and 7 deletions
|
|
@ -34,6 +34,62 @@ pub struct TargetCommand {
|
|||
stdin: Option<File>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
enum TargetStdinAccess {
|
||||
ReadOnly,
|
||||
WriteOnly,
|
||||
ReadWrite,
|
||||
}
|
||||
|
||||
impl TargetStdinAccess {
|
||||
fn from_flags(flags: OFlags) -> io::Result<Self> {
|
||||
if flags.contains(OFlags::PATH) {
|
||||
return Err(io::Error::other(
|
||||
"target stdin descriptor has no read or write authority",
|
||||
));
|
||||
}
|
||||
match flags & OFlags::ACCMODE {
|
||||
flags if flags == OFlags::RDONLY => Ok(Self::ReadOnly),
|
||||
flags if flags == OFlags::WRONLY => Ok(Self::WriteOnly),
|
||||
flags if flags == OFlags::RDWR => Ok(Self::ReadWrite),
|
||||
_ => Err(io::Error::other(
|
||||
"target stdin descriptor has an unsupported access mode",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_descriptor(descriptor: i32) -> io::Result<Self> {
|
||||
let metadata = std::fs::read_to_string(format!("/proc/self/fdinfo/{descriptor}"))?;
|
||||
let flags = metadata
|
||||
.lines()
|
||||
.find_map(|line| line.strip_prefix("flags:"))
|
||||
.map(str::trim)
|
||||
.ok_or_else(|| io::Error::other("target stdin descriptor flags are missing"))
|
||||
.and_then(|flags| {
|
||||
u32::from_str_radix(flags, 8)
|
||||
.map(OFlags::from_bits_retain)
|
||||
.map_err(|_| io::Error::other("target stdin descriptor flags are invalid"))
|
||||
})?;
|
||||
Self::from_flags(flags)
|
||||
}
|
||||
|
||||
fn reopen(self, descriptor: i32) -> io::Result<File> {
|
||||
let mut options = File::options();
|
||||
match self {
|
||||
Self::ReadOnly => {
|
||||
options.read(true);
|
||||
}
|
||||
Self::WriteOnly => {
|
||||
options.write(true);
|
||||
}
|
||||
Self::ReadWrite => {
|
||||
options.read(true).write(true);
|
||||
}
|
||||
}
|
||||
options.open(format!("/proc/self/fd/{descriptor}"))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum ParentEdge {
|
||||
ParentDeathKill,
|
||||
|
|
@ -93,6 +149,7 @@ impl TargetCommand {
|
|||
/// # 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> {
|
||||
TargetStdinAccess::from_flags(fcntl_getfl(&stdin)?)?;
|
||||
fcntl_setfd(stdin.as_fd(), FdFlags::empty())?;
|
||||
self.stdin = Some(stdin);
|
||||
Ok(self)
|
||||
|
|
@ -1373,15 +1430,11 @@ pub fn parse_wrapper_arguments(
|
|||
.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"))?;
|
||||
let access = TargetStdinAccess::from_descriptor(descriptor)?;
|
||||
if arguments.next().as_deref() != Some(OsStr::new("--")) {
|
||||
return Err(io::Error::other("wrapper target separator is missing"));
|
||||
}
|
||||
Some(
|
||||
File::options()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.open(format!("/proc/self/fd/{descriptor}"))?,
|
||||
)
|
||||
Some(access.reopen(descriptor)?)
|
||||
} else if next.as_deref() == Some(OsStr::new("--")) {
|
||||
None
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Reference in a new issue