shell: better readline, rsh: allow builtin pubkey
This commit is contained in:
parent
f36436ee07
commit
89f4965460
@ -18,7 +18,7 @@ pub struct DebugOptions {
|
||||
impl Default for DebugOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
serial_level: LogLevel::Info,
|
||||
serial_level: LogLevel::Debug,
|
||||
display_level: LogLevel::Info,
|
||||
disable_program_trace: false,
|
||||
}
|
||||
|
2
userspace/Cargo.lock
generated
2
userspace/Cargo.lock
generated
@ -290,6 +290,7 @@ name = "cross"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"yggdrasil-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1323,6 +1324,7 @@ name = "shell"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"cross",
|
||||
"libc",
|
||||
"nom",
|
||||
"thiserror",
|
||||
|
@ -5,6 +5,9 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
[target.'cfg(target_os = "yggdrasil")'.dependencies]
|
||||
yggdrasil-rt.workspace = true
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "*"
|
||||
|
||||
|
@ -1,12 +1,14 @@
|
||||
use std::{
|
||||
io::{self, Read, Write},
|
||||
io::{self, Read, Stdin, Write},
|
||||
ops::{Deref, DerefMut},
|
||||
os::fd::{AsRawFd, RawFd},
|
||||
process::Stdio,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use crate::sys::{
|
||||
self, PidFd as SysPidFd, Pipe as SysPipe, Poll as SysPoll, TimerFd as SysTimerFd,
|
||||
self, PidFd as SysPidFd, Pipe as SysPipe, Poll as SysPoll, RawStdin as SysRawStdin,
|
||||
TimerFd as SysTimerFd,
|
||||
};
|
||||
|
||||
use self::sys::PipeImpl;
|
||||
@ -23,6 +25,9 @@ pub struct PidFd(sys::PidFdImpl);
|
||||
#[repr(transparent)]
|
||||
pub struct Pipe(sys::PipeImpl);
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct RawStdin<'a>(sys::RawStdinImpl<'a>);
|
||||
|
||||
impl Poll {
|
||||
pub fn new() -> io::Result<Self> {
|
||||
sys::PollImpl::new().map(Self)
|
||||
@ -115,3 +120,29 @@ impl AsRawFd for Pipe {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> RawStdin<'a> {
|
||||
pub fn new(stdin: &'a mut Stdin) -> io::Result<Self> {
|
||||
sys::RawStdinImpl::new(stdin).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for RawStdin<'_> {
|
||||
type Target = Stdin;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.0.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for RawStdin<'_> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.0.deref_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for RawStdin<'_> {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,8 @@ mod unix;
|
||||
pub(crate) use unix::*;
|
||||
|
||||
use std::{
|
||||
io::{self, Read, Write},
|
||||
io::{self, Read, Stdin, Write},
|
||||
ops::DerefMut,
|
||||
os::fd::{AsRawFd, RawFd},
|
||||
process::Stdio,
|
||||
time::Duration,
|
||||
@ -37,3 +38,7 @@ pub(crate) trait Pipe: Read + Write + AsRawFd + Sized {
|
||||
fn new(read_nonblocking: bool, write_nonblocking: bool) -> io::Result<(Self, Self)>;
|
||||
fn to_child_stdio(&self) -> Stdio;
|
||||
}
|
||||
|
||||
pub(crate) trait RawStdin<'a>: Sized + DerefMut<Target = Stdin> + 'a {
|
||||
fn new(stdin: &'a mut Stdin) -> io::Result<Self>;
|
||||
}
|
||||
|
@ -2,8 +2,10 @@ pub mod poll;
|
||||
pub mod timer;
|
||||
pub mod pid;
|
||||
pub mod pipe;
|
||||
pub mod term;
|
||||
|
||||
pub use poll::PollImpl;
|
||||
pub use timer::TimerFdImpl;
|
||||
pub use pid::PidFdImpl;
|
||||
pub use pipe::PipeImpl;
|
||||
pub use term::RawStdinImpl;
|
||||
|
54
userspace/lib/cross/src/sys/unix/term.rs
Normal file
54
userspace/lib/cross/src/sys/unix/term.rs
Normal file
@ -0,0 +1,54 @@
|
||||
use std::{
|
||||
io::{self, Stdin},
|
||||
mem::MaybeUninit,
|
||||
ops::{Deref, DerefMut},
|
||||
os::fd::AsRawFd,
|
||||
};
|
||||
|
||||
use crate::sys::RawStdin;
|
||||
|
||||
pub struct RawStdinImpl<'a> {
|
||||
inner: &'a mut Stdin,
|
||||
saved: libc::termios,
|
||||
}
|
||||
|
||||
impl<'a> RawStdin<'a> for RawStdinImpl<'a> {
|
||||
fn new(stdin: &'a mut Stdin) -> io::Result<Self> {
|
||||
let mut saved = MaybeUninit::uninit();
|
||||
if unsafe { libc::tcgetattr(stdin.as_raw_fd(), saved.as_mut_ptr()) } != 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
let saved = unsafe { saved.assume_init() };
|
||||
let mut new = saved;
|
||||
unsafe { libc::cfmakeraw(&mut new) }
|
||||
if unsafe { libc::tcsetattr(stdin.as_raw_fd(), libc::TCSANOW, &new) } != 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
Ok(Self {
|
||||
inner: stdin,
|
||||
saved,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RawStdinImpl<'_> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
libc::tcsetattr(self.inner.as_raw_fd(), libc::TCSANOW, &self.saved);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for RawStdinImpl<'_> {
|
||||
type Target = Stdin;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for RawStdinImpl<'_> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.inner
|
||||
}
|
||||
}
|
@ -2,8 +2,10 @@ pub mod poll;
|
||||
pub mod timer;
|
||||
pub mod pid;
|
||||
pub mod pipe;
|
||||
pub mod term;
|
||||
|
||||
pub use poll::PollImpl;
|
||||
pub use timer::TimerFdImpl;
|
||||
pub use pid::PidFdImpl;
|
||||
pub use pipe::PipeImpl;
|
||||
pub use term::RawStdinImpl;
|
||||
|
47
userspace/lib/cross/src/sys/yggdrasil/term.rs
Normal file
47
userspace/lib/cross/src/sys/yggdrasil/term.rs
Normal file
@ -0,0 +1,47 @@
|
||||
use std::{
|
||||
io::{self, Stdin},
|
||||
ops::{Deref, DerefMut},
|
||||
os::{
|
||||
fd::AsRawFd,
|
||||
yggdrasil::io::terminal::{update_terminal_options, TerminalOptions},
|
||||
},
|
||||
};
|
||||
|
||||
use crate::sys::RawStdin;
|
||||
|
||||
pub struct RawStdinImpl<'a> {
|
||||
inner: &'a mut Stdin,
|
||||
saved: TerminalOptions,
|
||||
}
|
||||
|
||||
impl<'a> RawStdin<'a> for RawStdinImpl<'a> {
|
||||
fn new(stdin: &'a mut Stdin) -> io::Result<Self> {
|
||||
let saved = unsafe {
|
||||
update_terminal_options(stdin.as_raw_fd(), |_| TerminalOptions::raw_input())
|
||||
}?;
|
||||
Ok(Self {
|
||||
inner: stdin,
|
||||
saved,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RawStdinImpl<'_> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { update_terminal_options(self.inner.as_raw_fd(), |_| self.saved).ok() };
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for RawStdinImpl<'_> {
|
||||
type Target = Stdin;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for RawStdinImpl<'_> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.inner
|
||||
}
|
||||
}
|
@ -10,3 +10,6 @@ thiserror.workspace = true
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2.150"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
@ -6,14 +6,14 @@ use std::{
|
||||
|
||||
pub use self::{input::ReadChar, sys::RawMode};
|
||||
|
||||
#[cfg(target_os = "yggdrasil")]
|
||||
#[cfg(any(target_os = "yggdrasil", rust_analyzer))]
|
||||
mod yggdrasil;
|
||||
#[cfg(target_os = "yggdrasil")]
|
||||
#[cfg(any(target_os = "yggdrasil", rust_analyzer))]
|
||||
use yggdrasil as sys;
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(any(unix, rust_analyzer))]
|
||||
mod unix;
|
||||
#[cfg(unix)]
|
||||
#[cfg(any(unix, rust_analyzer))]
|
||||
use unix as sys;
|
||||
|
||||
mod input;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use std::{
|
||||
io::{self, Stdin, Stdout},
|
||||
io::{self, Stdout},
|
||||
mem::MaybeUninit,
|
||||
os::fd::AsRawFd,
|
||||
};
|
||||
@ -9,7 +9,7 @@ pub struct RawMode {
|
||||
}
|
||||
|
||||
impl RawMode {
|
||||
pub unsafe fn enter(stdin: &Stdin) -> Result<Self, io::Error> {
|
||||
pub unsafe fn enter<F: AsRawFd>(stdin: &F) -> Result<Self, io::Error> {
|
||||
let mut old = MaybeUninit::uninit();
|
||||
|
||||
if libc::tcgetattr(stdin.as_raw_fd(), old.as_mut_ptr()) != 0 {
|
||||
@ -39,7 +39,7 @@ impl RawMode {
|
||||
Ok(Self { saved_termios: old })
|
||||
}
|
||||
|
||||
pub unsafe fn leave(&self, stdin: &Stdin) {
|
||||
pub unsafe fn leave<F: AsRawFd>(&self, stdin: &F) {
|
||||
libc::tcsetattr(stdin.as_raw_fd(), libc::TCSANOW, &self.saved_termios);
|
||||
}
|
||||
}
|
||||
|
@ -22,3 +22,6 @@ log.workspace = true
|
||||
rand = { git = "https://git.alnyan.me/yggdrasil/rand.git", branch = "alnyan/yggdrasil-rng_core-0.6.4" }
|
||||
aes = { version = "0.8.4" }
|
||||
env_logger = "0.11.5"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
@ -1,8 +1,7 @@
|
||||
#![cfg_attr(target_os = "yggdrasil", feature(yggdrasil_os, rustc_private))]
|
||||
#![feature(if_let_guard)]
|
||||
use std::{
|
||||
collections::HashSet, net::SocketAddr, path::PathBuf, process::ExitCode, str::FromStr,
|
||||
time::Duration,
|
||||
collections::HashSet, net::SocketAddr, os::fd::{self, IntoRawFd}, path::PathBuf, process::ExitCode, str::FromStr, time::Duration
|
||||
};
|
||||
|
||||
use clap::Parser;
|
||||
@ -63,14 +62,17 @@ impl rsh::server::Session for YggdrasilSession {
|
||||
},
|
||||
)?;
|
||||
|
||||
let pty_slave_fd = pty_slave.as_raw_fd();
|
||||
let pty_slave_stdin = pty_slave.into_raw_fd();
|
||||
let pty_slave_stdout = fd::clone_fd(pty_slave_stdin)?;
|
||||
let pty_slave_stderr = fd::clone_fd(pty_slave_stdin)?;
|
||||
|
||||
let group_id = yggdrasil::process::create_process_group();
|
||||
let shell = unsafe {
|
||||
Command::new("/bin/sh")
|
||||
.arg("-l")
|
||||
.stdin(Stdio::from_raw_fd(pty_slave_fd))
|
||||
.stdout(Stdio::from_raw_fd(pty_slave_fd))
|
||||
.stderr(Stdio::from_raw_fd(pty_slave_fd))
|
||||
.stdin(Stdio::from_raw_fd(pty_slave_stdin))
|
||||
.stdout(Stdio::from_raw_fd(pty_slave_stdout))
|
||||
.stderr(Stdio::from_raw_fd(pty_slave_stderr))
|
||||
.process_group(group_id)
|
||||
.gain_terminal(0)
|
||||
.spawn()?
|
||||
@ -129,9 +131,9 @@ impl rsh::server::Session for YggdrasilSession {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(any(unix, rust_analyzer))]
|
||||
pub type SessionImpl = rsh::server::EchoSession;
|
||||
#[cfg(target_os = "yggdrasil")]
|
||||
#[cfg(any(target_os = "yggdrasil", rust_analyzer))]
|
||||
pub type SessionImpl = YggdrasilSession;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
@ -144,7 +146,7 @@ fn run(args: Args) -> Result<(), Error> {
|
||||
let keystore = SimpleServerKeyStore {
|
||||
path: args.keystore,
|
||||
accepted_keys: HashSet::from_iter([
|
||||
"ed25519 sha256 63:f4:df:41:c3:ec:a7:7c:ea:f1:65:22:91:8b:14:60:8f:ec:cd:19:90:2e:12:33:66:e3:33:24:96:3d:63:c3".into()
|
||||
"ed25519 sha256 ab:5d:d8:a9:56:79:f9:0f:47:32:a4:4b:f5:fb:49:2d:3d:91:a7:7d:70:60:8a:57:84:36:43:80:7e:91:8a:c3".into()
|
||||
]),
|
||||
};
|
||||
let server_config = ServerConfig::with_default_algorithms(keystore);
|
||||
|
@ -5,6 +5,8 @@ edition = "2021"
|
||||
authors = ["Mark Poliakov <mark@alnyan.me>"]
|
||||
|
||||
[dependencies]
|
||||
cross.workspace = true
|
||||
|
||||
clap.workspace = true
|
||||
thiserror.workspace = true
|
||||
|
||||
|
@ -15,6 +15,7 @@ use parser::Command;
|
||||
|
||||
mod builtins;
|
||||
mod parser;
|
||||
mod readline;
|
||||
mod sys;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
@ -68,16 +69,27 @@ impl Outcome {
|
||||
}
|
||||
|
||||
impl Input {
|
||||
pub fn getline(&mut self, buf: &mut String) -> io::Result<usize> {
|
||||
pub fn getline(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
match self {
|
||||
Self::Interactive(input) => {
|
||||
let mut stdout = stdout();
|
||||
print!("$ ");
|
||||
stdout.flush().ok();
|
||||
|
||||
input.read_line(buf)
|
||||
readline::readline(input, &mut stdout, buf, |stdout| {
|
||||
let cwd = env::current_dir();
|
||||
let cwd = match cwd {
|
||||
Ok(cwd) => format!("{}", cwd.display()),
|
||||
Err(_) => "???".into(),
|
||||
};
|
||||
let prompt = format!("{cwd} $ ");
|
||||
stdout.write_all(prompt.as_bytes()).ok();
|
||||
})
|
||||
}
|
||||
Self::File(input) => {
|
||||
let mut string = String::new();
|
||||
input.read_line(&mut string)?;
|
||||
buf[..string.len()].copy_from_slice(string.as_bytes());
|
||||
Ok(string.len())
|
||||
}
|
||||
Self::File(input) => input.read_line(buf),
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,15 +189,16 @@ pub fn exec(
|
||||
Ok(status)
|
||||
}
|
||||
|
||||
fn run(mut input: Input, vars: &mut HashMap<String, String>) -> io::Result<ExitCode> {
|
||||
let mut line = String::new();
|
||||
fn run(mut input: Input, vars: &mut HashMap<String, String>) -> Result<ExitCode, Error> {
|
||||
// let mut line = String::new();
|
||||
let mut line = [0; 4096];
|
||||
|
||||
if input.is_interactive() {
|
||||
sys::init_signal_handler();
|
||||
}
|
||||
|
||||
let code = loop {
|
||||
line.clear();
|
||||
// line.clear();
|
||||
|
||||
let len = input.getline(&mut line)?;
|
||||
|
||||
@ -193,6 +206,9 @@ fn run(mut input: Input, vars: &mut HashMap<String, String>) -> io::Result<ExitC
|
||||
break ExitCode::SUCCESS;
|
||||
}
|
||||
|
||||
let Ok(line) = std::str::from_utf8(&line[..len]) else {
|
||||
continue;
|
||||
};
|
||||
let line = line.trim();
|
||||
let line = match line.split_once('#') {
|
||||
Some((line, _)) => line.trim(),
|
||||
@ -233,12 +249,12 @@ fn run(mut input: Input, vars: &mut HashMap<String, String>) -> io::Result<ExitC
|
||||
Ok(code)
|
||||
}
|
||||
|
||||
fn run_file<P: AsRef<Path>>(path: P, env: &mut HashMap<String, String>) -> io::Result<ExitCode> {
|
||||
fn run_file<P: AsRef<Path>>(path: P, env: &mut HashMap<String, String>) -> Result<ExitCode, Error> {
|
||||
let input = BufReader::new(File::open(path)?);
|
||||
run(Input::File(input), env)
|
||||
}
|
||||
|
||||
fn run_stdin(env: &mut HashMap<String, String>) -> io::Result<ExitCode> {
|
||||
fn run_stdin(env: &mut HashMap<String, String>) -> Result<ExitCode, Error> {
|
||||
run(Input::Interactive(stdin()), env)
|
||||
}
|
||||
|
||||
@ -267,8 +283,8 @@ fn main() -> ExitCode {
|
||||
|
||||
match result {
|
||||
Ok(_) => ExitCode::SUCCESS,
|
||||
Err(e) => {
|
||||
eprintln!("{:?}", e);
|
||||
Err(error) => {
|
||||
eprintln!("{error}");
|
||||
ExitCode::FAILURE
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ fn parse_command(_env: &HashMap<String, String>, input: &[Token]) -> Result<Comm
|
||||
|
||||
let mut current = vec![];
|
||||
|
||||
let mut it = input.into_iter();
|
||||
let mut it = input.iter();
|
||||
while let Some(token) = it.next() {
|
||||
match token {
|
||||
&Token::Word(word) => {
|
||||
@ -85,7 +85,7 @@ fn parse_command(_env: &HashMap<String, String>, input: &[Token]) -> Result<Comm
|
||||
}
|
||||
|
||||
elements.push(PipelineElement {
|
||||
words: mem::replace(&mut current, vec![]),
|
||||
words: mem::take(&mut current)
|
||||
});
|
||||
}
|
||||
Token::Output(1) => {
|
||||
|
85
userspace/shell/src/readline.rs
Normal file
85
userspace/shell/src/readline.rs
Normal file
@ -0,0 +1,85 @@
|
||||
use std::io::{Read, Stdin, Stdout, Write};
|
||||
|
||||
use cross::io::RawStdin;
|
||||
|
||||
use crate::Error;
|
||||
|
||||
enum Outcome {
|
||||
Interrupt,
|
||||
Data(usize),
|
||||
}
|
||||
|
||||
fn readline_inner(stdin: &mut RawStdin, stdout: &mut Stdout, buffer: &mut [u8]) -> Result<Outcome, Error> {
|
||||
let mut pos = 0;
|
||||
let mut ch = [0];
|
||||
|
||||
while pos < buffer.len() {
|
||||
let len = stdin.read(&mut ch)?;
|
||||
if len == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let ch = ch[0];
|
||||
|
||||
match ch {
|
||||
// ^D
|
||||
0x04 => {
|
||||
if pos == 0 {
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// ^C
|
||||
0x03 => return Ok(Outcome::Interrupt),
|
||||
// TODO completion
|
||||
b'\t' => (),
|
||||
0x7F => {
|
||||
if pos != 0 {
|
||||
stdout.write_all(b"\x1B[D \x1B[D").ok();
|
||||
stdout.flush().ok();
|
||||
pos -= 1;
|
||||
}
|
||||
}
|
||||
ch if ch.is_ascii_graphic() || ch.is_ascii_whitespace() => {
|
||||
stdout.write_all(&[ch]).ok();
|
||||
stdout.flush().ok();
|
||||
|
||||
buffer[pos] = ch;
|
||||
pos += 1;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if ch == b'\n' || ch == b'\r' {
|
||||
if ch == b'\r' {
|
||||
stdout.write_all(b"\n").ok();
|
||||
stdout.flush().ok();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Outcome::Data(pos))
|
||||
}
|
||||
|
||||
pub fn readline<P: Fn(&mut Stdout)>(
|
||||
stdin: &mut Stdin,
|
||||
stdout: &mut Stdout,
|
||||
buffer: &mut [u8],
|
||||
prompt: P
|
||||
) -> Result<usize, Error> {
|
||||
let mut stdin = RawStdin::new(stdin)?;
|
||||
|
||||
loop {
|
||||
prompt(stdout);
|
||||
stdout.flush().ok();
|
||||
|
||||
match readline_inner(&mut stdin, stdout, buffer)? {
|
||||
Outcome::Data(n) => break Ok(n),
|
||||
Outcome::Interrupt => {
|
||||
stdout.write_all(b"\r\n").ok();
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,10 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
io,
|
||||
os::{
|
||||
fd::{FromRawFd, OwnedFd, RawFd},
|
||||
unix::process::{CommandExt, ExitStatusExt},
|
||||
fd::{FromRawFd, OwnedFd},
|
||||
unix::process::ExitStatusExt,
|
||||
},
|
||||
process::{Child, Command, ExitStatus, Stdio},
|
||||
process::{Command, ExitStatus},
|
||||
};
|
||||
|
||||
use crate::{Outcome, Pipeline, SpawnedPipeline};
|
||||
@ -15,30 +14,6 @@ pub struct Pipe {
|
||||
pub write: OwnedFd,
|
||||
}
|
||||
|
||||
pub fn exec_binary(
|
||||
interactive: bool,
|
||||
binary: &str,
|
||||
args: &[String],
|
||||
env: &HashMap<String, String>,
|
||||
input: Stdio,
|
||||
output: Stdio,
|
||||
) -> Result<Child, io::Error> {
|
||||
let mut command = Command::new(binary);
|
||||
let mut command = command
|
||||
.args(args)
|
||||
.envs(env.iter())
|
||||
.stdin(input)
|
||||
.stdout(output);
|
||||
|
||||
if interactive {
|
||||
unsafe {
|
||||
command = command.process_group(0);
|
||||
}
|
||||
}
|
||||
|
||||
command.spawn()
|
||||
}
|
||||
|
||||
pub fn create_pipe() -> Result<Pipe, io::Error> {
|
||||
let mut fds = [0; 2];
|
||||
let (read, write) = unsafe {
|
||||
@ -67,7 +42,7 @@ impl From<ExitStatus> for Outcome {
|
||||
pub fn init_signal_handler() {}
|
||||
|
||||
pub fn spawn_pipeline(
|
||||
interactive: bool,
|
||||
_interactive: bool,
|
||||
pipeline: Pipeline<'_>,
|
||||
) -> Result<SpawnedPipeline, io::Error> {
|
||||
let mut children = vec![];
|
||||
@ -86,7 +61,7 @@ pub fn spawn_pipeline(
|
||||
}
|
||||
|
||||
pub fn wait_for_pipeline(
|
||||
interactive: bool,
|
||||
_interactive: bool,
|
||||
mut pipeline: SpawnedPipeline,
|
||||
) -> Result<Outcome, io::Error> {
|
||||
for mut child in pipeline.children.drain(..) {
|
||||
@ -94,22 +69,4 @@ pub fn wait_for_pipeline(
|
||||
}
|
||||
|
||||
Ok(Outcome::ok())
|
||||
// let self_group_id = process::group_id();
|
||||
|
||||
// for mut child in pipeline.children.drain(..) {
|
||||
// let status = child.wait()?;
|
||||
|
||||
// if !status.success() {
|
||||
// if interactive {
|
||||
// set_terminal_group(self_group_id).ok();
|
||||
// }
|
||||
// return Ok(Outcome::from(status));
|
||||
// }
|
||||
// }
|
||||
|
||||
// if interactive {
|
||||
// set_terminal_group(self_group_id).ok();
|
||||
// }
|
||||
|
||||
// Ok(Outcome::ok())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user