mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-04 06:19:44 +00:00
fix shell support in package attach (#2929)
* fix package attach * final fixes * apply changes to launch * Update core/startos/src/service/effects/subcontainer/sync.rs
This commit is contained in:
@@ -1,19 +1,22 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::ffi::{c_int, OsStr, OsString};
|
||||
use std::fs::File;
|
||||
use std::io::IsTerminal;
|
||||
use std::io::{IsTerminal, Read};
|
||||
use std::os::unix::process::CommandExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command as StdCommand, Stdio};
|
||||
use std::sync::Arc;
|
||||
|
||||
use nix::sched::CloneFlags;
|
||||
use nix::unistd::Pid;
|
||||
use signal_hook::consts::signal::*;
|
||||
use termion::raw::IntoRawMode;
|
||||
use tokio::sync::oneshot;
|
||||
use tty_spawn::TtySpawn;
|
||||
|
||||
use crate::service::effects::prelude::*;
|
||||
use crate::service::effects::ContainerCliContext;
|
||||
use crate::util::io::TermSize;
|
||||
use crate::CAP_1_KiB;
|
||||
|
||||
const FWD_SIGNALS: &[c_int] = &[
|
||||
SIGABRT, SIGALRM, SIGCONT, SIGHUP, SIGINT, SIGIO, SIGPIPE, SIGPROF, SIGQUIT, SIGTERM, SIGTRAP,
|
||||
@@ -98,6 +101,10 @@ fn open_file_read(path: impl AsRef<Path>) -> Result<File, Error> {
|
||||
pub struct ExecParams {
|
||||
#[arg(long)]
|
||||
force_tty: bool,
|
||||
#[arg(long)]
|
||||
force_stderr_tty: bool,
|
||||
#[arg(long)]
|
||||
pty_size: Option<TermSize>,
|
||||
#[arg(short, long)]
|
||||
env: Option<PathBuf>,
|
||||
#[arg(short, long)]
|
||||
@@ -181,6 +188,8 @@ pub fn launch(
|
||||
_: ContainerCliContext,
|
||||
ExecParams {
|
||||
force_tty,
|
||||
force_stderr_tty,
|
||||
pty_size,
|
||||
env,
|
||||
workdir,
|
||||
user,
|
||||
@@ -188,34 +197,9 @@ pub fn launch(
|
||||
command,
|
||||
}: ExecParams,
|
||||
) -> Result<(), Error> {
|
||||
kill_init(Path::new("/proc"), &chroot)?;
|
||||
if (std::io::stdin().is_terminal()
|
||||
&& std::io::stdout().is_terminal()
|
||||
&& std::io::stderr().is_terminal())
|
||||
|| force_tty
|
||||
{
|
||||
let mut cmd = TtySpawn::new("/usr/bin/start-cli");
|
||||
cmd.arg("subcontainer").arg("launch-init");
|
||||
if let Some(env) = env {
|
||||
cmd.arg("--env").arg(env);
|
||||
}
|
||||
if let Some(workdir) = workdir {
|
||||
cmd.arg("--workdir").arg(workdir);
|
||||
}
|
||||
if let Some(user) = user {
|
||||
cmd.arg("--user").arg(user);
|
||||
}
|
||||
cmd.arg(&chroot);
|
||||
cmd.args(command.iter());
|
||||
nix::sched::unshare(CloneFlags::CLONE_NEWPID)
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "unshare pid ns"))?;
|
||||
nix::sched::unshare(CloneFlags::CLONE_NEWCGROUP)
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "unshare cgroup ns"))?;
|
||||
nix::sched::unshare(CloneFlags::CLONE_NEWIPC)
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "unshare ipc ns"))?;
|
||||
std::process::exit(cmd.spawn().with_kind(ErrorKind::Filesystem)?);
|
||||
}
|
||||
use std::io::Write;
|
||||
|
||||
kill_init(Path::new("/proc"), &chroot)?;
|
||||
let mut sig = signal_hook::iterator::Signals::new(FWD_SIGNALS)?;
|
||||
let (send_pid, recv_pid) = oneshot::channel();
|
||||
std::thread::spawn(move || {
|
||||
@@ -229,75 +213,181 @@ pub fn launch(
|
||||
}
|
||||
}
|
||||
});
|
||||
let mut cmd = StdCommand::new("/usr/bin/start-cli");
|
||||
cmd.arg("subcontainer").arg("launch-init");
|
||||
if let Some(env) = env {
|
||||
cmd.arg("--env").arg(env);
|
||||
}
|
||||
if let Some(workdir) = workdir {
|
||||
cmd.arg("--workdir").arg(workdir);
|
||||
}
|
||||
if let Some(user) = user {
|
||||
cmd.arg("--user").arg(user);
|
||||
}
|
||||
cmd.arg(&chroot);
|
||||
cmd.args(&command);
|
||||
cmd.stdin(Stdio::piped());
|
||||
cmd.stdout(Stdio::piped());
|
||||
cmd.stderr(Stdio::piped());
|
||||
let (stdin_send, stdin_recv) = oneshot::channel();
|
||||
|
||||
let mut stdin = std::io::stdin();
|
||||
let stdout = std::io::stdout();
|
||||
let stderr = std::io::stderr();
|
||||
let stderr_tty = force_stderr_tty || stderr.is_terminal();
|
||||
|
||||
let tty = force_tty || (stdin.is_terminal() && stdout.is_terminal());
|
||||
|
||||
let raw = if stdin.is_terminal() && stdout.is_terminal() {
|
||||
Some(termion::get_tty()?.into_raw_mode()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let pty_size = pty_size.or_else(|| TermSize::get_current());
|
||||
|
||||
let (stdin_send, stdin_recv) = oneshot::channel::<Box<dyn Write + Send>>();
|
||||
std::thread::spawn(move || {
|
||||
if let Ok(mut stdin) = stdin_recv.blocking_recv() {
|
||||
std::io::copy(&mut std::io::stdin(), &mut stdin).unwrap();
|
||||
if let Ok(mut cstdin) = stdin_recv.blocking_recv() {
|
||||
if tty {
|
||||
let mut buf = [0_u8; CAP_1_KiB];
|
||||
while let Ok(n) = stdin.read(&mut buf) {
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
cstdin.write_all(&buf[..n]).ok();
|
||||
cstdin.flush().ok();
|
||||
}
|
||||
} else {
|
||||
std::io::copy(&mut stdin, &mut cstdin).unwrap();
|
||||
}
|
||||
}
|
||||
});
|
||||
let (stdout_send, stdout_recv) = oneshot::channel();
|
||||
std::thread::spawn(move || {
|
||||
if let Ok(mut stdout) = stdout_recv.blocking_recv() {
|
||||
std::io::copy(&mut stdout, &mut std::io::stdout()).unwrap();
|
||||
}
|
||||
});
|
||||
let (stderr_send, stderr_recv) = oneshot::channel();
|
||||
std::thread::spawn(move || {
|
||||
if let Ok(mut stderr) = stderr_recv.blocking_recv() {
|
||||
std::io::copy(&mut stderr, &mut std::io::stderr()).unwrap();
|
||||
let (stdout_send, stdout_recv) = oneshot::channel::<Box<dyn std::io::Read + Send>>();
|
||||
let stdout_thread = std::thread::spawn(move || {
|
||||
if let Ok(mut cstdout) = stdout_recv.blocking_recv() {
|
||||
if tty {
|
||||
let mut stdout = stdout.lock();
|
||||
let mut buf = [0_u8; CAP_1_KiB];
|
||||
while let Ok(n) = cstdout.read(&mut buf) {
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
stdout.write_all(&buf[..n]).ok();
|
||||
stdout.flush().ok();
|
||||
}
|
||||
} else {
|
||||
std::io::copy(&mut cstdout, &mut stdout.lock()).unwrap();
|
||||
}
|
||||
}
|
||||
});
|
||||
let (stderr_send, stderr_recv) = oneshot::channel::<Box<dyn std::io::Read + Send>>();
|
||||
let stderr_thread = if !stderr_tty {
|
||||
Some(std::thread::spawn(move || {
|
||||
if let Ok(mut cstderr) = stderr_recv.blocking_recv() {
|
||||
std::io::copy(&mut cstderr, &mut stderr.lock()).unwrap();
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
nix::sched::unshare(CloneFlags::CLONE_NEWPID)
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "unshare pid ns"))?;
|
||||
nix::sched::unshare(CloneFlags::CLONE_NEWCGROUP)
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "unshare cgroup ns"))?;
|
||||
nix::sched::unshare(CloneFlags::CLONE_NEWIPC)
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "unshare ipc ns"))?;
|
||||
let mut child = cmd
|
||||
.spawn()
|
||||
.map_err(color_eyre::eyre::Report::msg)
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "spawning child process"))?;
|
||||
send_pid.send(child.id() as i32).unwrap_or_default();
|
||||
stdin_send
|
||||
.send(child.stdin.take().unwrap())
|
||||
.unwrap_or_default();
|
||||
stdout_send
|
||||
.send(child.stdout.take().unwrap())
|
||||
.unwrap_or_default();
|
||||
stderr_send
|
||||
.send(child.stderr.take().unwrap())
|
||||
.unwrap_or_default();
|
||||
// TODO: subreaping, signal handling
|
||||
let exit = child
|
||||
.wait()
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "waiting on child process"))?;
|
||||
if let Some(code) = exit.code() {
|
||||
nix::mount::umount(&chroot.join("proc"))
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "umount procfs"))?;
|
||||
std::process::exit(code);
|
||||
} else if exit.success() {
|
||||
Ok(())
|
||||
|
||||
if tty {
|
||||
use pty_process::blocking as pty_process;
|
||||
let (pty, pts) = pty_process::open().with_kind(ErrorKind::Filesystem)?;
|
||||
let mut cmd = pty_process::Command::new("/usr/bin/start-cli");
|
||||
cmd = cmd.arg("subcontainer").arg("launch-init");
|
||||
if let Some(env) = env {
|
||||
cmd = cmd.arg("--env").arg(env);
|
||||
}
|
||||
if let Some(workdir) = workdir {
|
||||
cmd = cmd.arg("--workdir").arg(workdir);
|
||||
}
|
||||
if let Some(user) = user {
|
||||
cmd = cmd.arg("--user").arg(user);
|
||||
}
|
||||
cmd = cmd.arg(&chroot).args(&command);
|
||||
if !stderr_tty {
|
||||
cmd = cmd.stderr(Stdio::piped());
|
||||
}
|
||||
let mut child = cmd
|
||||
.spawn(pts)
|
||||
.map_err(color_eyre::eyre::Report::msg)
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "spawning child process"))?;
|
||||
send_pid.send(child.id() as i32).unwrap_or_default();
|
||||
if let Some(pty_size) = pty_size {
|
||||
let size = if let Some((x, y)) = pty_size.pixels {
|
||||
::pty_process::Size::new_with_pixel(pty_size.size.0, pty_size.size.1, x, y)
|
||||
} else {
|
||||
::pty_process::Size::new(pty_size.size.0, pty_size.size.1)
|
||||
};
|
||||
pty.resize(size).with_kind(ErrorKind::Filesystem)?;
|
||||
}
|
||||
let shared = ArcPty(Arc::new(pty));
|
||||
stdin_send
|
||||
.send(Box::new(shared.clone()))
|
||||
.unwrap_or_default();
|
||||
stdout_send
|
||||
.send(Box::new(shared.clone()))
|
||||
.unwrap_or_default();
|
||||
if let Some(stderr) = child.stderr.take() {
|
||||
stderr_send.send(Box::new(stderr)).unwrap_or_default();
|
||||
}
|
||||
let exit = child
|
||||
.wait()
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "waiting on child process"))?;
|
||||
stdout_thread.join().unwrap();
|
||||
stderr_thread.map(|t| t.join().unwrap());
|
||||
if let Some(code) = exit.code() {
|
||||
drop(raw);
|
||||
std::process::exit(code);
|
||||
} else if exit.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(
|
||||
color_eyre::eyre::Report::msg(exit),
|
||||
ErrorKind::Unknown,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Err(Error::new(
|
||||
color_eyre::eyre::Report::msg(exit),
|
||||
ErrorKind::Unknown,
|
||||
))
|
||||
let mut cmd = StdCommand::new("/usr/bin/start-cli");
|
||||
cmd.arg("subcontainer").arg("launch-init");
|
||||
if let Some(env) = env {
|
||||
cmd.arg("--env").arg(env);
|
||||
}
|
||||
if let Some(workdir) = workdir {
|
||||
cmd.arg("--workdir").arg(workdir);
|
||||
}
|
||||
if let Some(user) = user {
|
||||
cmd.arg("--user").arg(user);
|
||||
}
|
||||
cmd.arg(&chroot);
|
||||
cmd.args(&command);
|
||||
cmd.stdin(Stdio::piped());
|
||||
cmd.stdout(Stdio::piped());
|
||||
cmd.stderr(Stdio::piped());
|
||||
let mut child = cmd
|
||||
.spawn()
|
||||
.map_err(color_eyre::eyre::Report::msg)
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "spawning child process"))?;
|
||||
send_pid.send(child.id() as i32).unwrap_or_default();
|
||||
stdin_send
|
||||
.send(Box::new(child.stdin.take().unwrap()))
|
||||
.unwrap_or_default();
|
||||
stdout_send
|
||||
.send(Box::new(child.stdout.take().unwrap()))
|
||||
.unwrap_or_default();
|
||||
stderr_send
|
||||
.send(Box::new(child.stderr.take().unwrap()))
|
||||
.unwrap_or_default();
|
||||
|
||||
// TODO: subreaping, signal handling
|
||||
let exit = child
|
||||
.wait()
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "waiting on child process"))?;
|
||||
stdout_thread.join().unwrap();
|
||||
stderr_thread.map(|t| t.join().unwrap());
|
||||
if let Some(code) = exit.code() {
|
||||
nix::mount::umount(&chroot.join("proc"))
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "umount procfs"))?;
|
||||
std::process::exit(code);
|
||||
} else if exit.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(
|
||||
color_eyre::eyre::Report::msg(exit),
|
||||
ErrorKind::Unknown,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,10 +410,28 @@ pub fn launch_init(_: ContainerCliContext, params: ExecParams) -> Result<(), Err
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ArcPty(Arc<pty_process::blocking::Pty>);
|
||||
impl std::io::Write for ArcPty {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
(&*self.0).write(buf)
|
||||
}
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
(&*self.0).flush()
|
||||
}
|
||||
}
|
||||
impl std::io::Read for ArcPty {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
(&*self.0).read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exec(
|
||||
_: ContainerCliContext,
|
||||
ExecParams {
|
||||
force_tty,
|
||||
force_stderr_tty,
|
||||
pty_size,
|
||||
env,
|
||||
workdir,
|
||||
user,
|
||||
@@ -331,41 +439,8 @@ pub fn exec(
|
||||
command,
|
||||
}: ExecParams,
|
||||
) -> Result<(), Error> {
|
||||
if (std::io::stdin().is_terminal()
|
||||
&& std::io::stdout().is_terminal()
|
||||
&& std::io::stderr().is_terminal())
|
||||
|| force_tty
|
||||
{
|
||||
let mut cmd = TtySpawn::new("/usr/bin/start-cli");
|
||||
cmd.arg("subcontainer").arg("exec-command");
|
||||
if let Some(env) = env {
|
||||
cmd.arg("--env").arg(env);
|
||||
}
|
||||
if let Some(workdir) = workdir {
|
||||
cmd.arg("--workdir").arg(workdir);
|
||||
}
|
||||
if let Some(user) = user {
|
||||
cmd.arg("--user").arg(user);
|
||||
}
|
||||
cmd.arg(&chroot);
|
||||
cmd.args(command.iter());
|
||||
nix::sched::setns(
|
||||
open_file_read(chroot.join("proc/1/ns/pid"))?,
|
||||
CloneFlags::CLONE_NEWPID,
|
||||
)
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "set pid ns"))?;
|
||||
nix::sched::setns(
|
||||
open_file_read(chroot.join("proc/1/ns/cgroup"))?,
|
||||
CloneFlags::CLONE_NEWCGROUP,
|
||||
)
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "set cgroup ns"))?;
|
||||
nix::sched::setns(
|
||||
open_file_read(chroot.join("proc/1/ns/ipc"))?,
|
||||
CloneFlags::CLONE_NEWIPC,
|
||||
)
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "set ipc ns"))?;
|
||||
std::process::exit(cmd.spawn().with_kind(ErrorKind::Filesystem)?);
|
||||
}
|
||||
use std::io::Write;
|
||||
|
||||
let mut sig = signal_hook::iterator::Signals::new(FWD_SIGNALS)?;
|
||||
let (send_pid, recv_pid) = oneshot::channel();
|
||||
std::thread::spawn(move || {
|
||||
@@ -379,40 +454,67 @@ pub fn exec(
|
||||
}
|
||||
}
|
||||
});
|
||||
let mut cmd = StdCommand::new("/usr/bin/start-cli");
|
||||
cmd.arg("subcontainer").arg("exec-command");
|
||||
if let Some(env) = env {
|
||||
cmd.arg("--env").arg(env);
|
||||
}
|
||||
if let Some(workdir) = workdir {
|
||||
cmd.arg("--workdir").arg(workdir);
|
||||
}
|
||||
if let Some(user) = user {
|
||||
cmd.arg("--user").arg(user);
|
||||
}
|
||||
cmd.arg(&chroot);
|
||||
cmd.args(&command);
|
||||
cmd.stdin(Stdio::piped());
|
||||
cmd.stdout(Stdio::piped());
|
||||
cmd.stderr(Stdio::piped());
|
||||
let (stdin_send, stdin_recv) = oneshot::channel();
|
||||
|
||||
let mut stdin = std::io::stdin();
|
||||
let stdout = std::io::stdout();
|
||||
let stderr = std::io::stderr();
|
||||
let stderr_tty = force_stderr_tty || stderr.is_terminal();
|
||||
|
||||
let tty = force_tty || (stdin.is_terminal() && stdout.is_terminal());
|
||||
|
||||
let raw = if stdin.is_terminal() && stdout.is_terminal() {
|
||||
Some(termion::get_tty()?.into_raw_mode()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let pty_size = pty_size.or_else(|| TermSize::get_current());
|
||||
|
||||
let (stdin_send, stdin_recv) = oneshot::channel::<Box<dyn Write + Send>>();
|
||||
std::thread::spawn(move || {
|
||||
if let Ok(mut stdin) = stdin_recv.blocking_recv() {
|
||||
std::io::copy(&mut std::io::stdin(), &mut stdin).unwrap();
|
||||
if let Ok(mut cstdin) = stdin_recv.blocking_recv() {
|
||||
if tty {
|
||||
let mut buf = [0_u8; CAP_1_KiB];
|
||||
while let Ok(n) = stdin.read(&mut buf) {
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
cstdin.write_all(&buf[..n]).ok();
|
||||
cstdin.flush().ok();
|
||||
}
|
||||
} else {
|
||||
std::io::copy(&mut stdin, &mut cstdin).unwrap();
|
||||
}
|
||||
}
|
||||
});
|
||||
let (stdout_send, stdout_recv) = oneshot::channel();
|
||||
std::thread::spawn(move || {
|
||||
if let Ok(mut stdout) = stdout_recv.blocking_recv() {
|
||||
std::io::copy(&mut stdout, &mut std::io::stdout()).unwrap();
|
||||
}
|
||||
});
|
||||
let (stderr_send, stderr_recv) = oneshot::channel();
|
||||
std::thread::spawn(move || {
|
||||
if let Ok(mut stderr) = stderr_recv.blocking_recv() {
|
||||
std::io::copy(&mut stderr, &mut std::io::stderr()).unwrap();
|
||||
let (stdout_send, stdout_recv) = oneshot::channel::<Box<dyn std::io::Read + Send>>();
|
||||
let stdout_thread = std::thread::spawn(move || {
|
||||
if let Ok(mut cstdout) = stdout_recv.blocking_recv() {
|
||||
if tty {
|
||||
let mut stdout = stdout.lock();
|
||||
let mut buf = [0_u8; CAP_1_KiB];
|
||||
while let Ok(n) = cstdout.read(&mut buf) {
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
stdout.write_all(&buf[..n]).ok();
|
||||
stdout.flush().ok();
|
||||
}
|
||||
} else {
|
||||
std::io::copy(&mut cstdout, &mut stdout.lock()).unwrap();
|
||||
}
|
||||
}
|
||||
});
|
||||
let (stderr_send, stderr_recv) = oneshot::channel::<Box<dyn std::io::Read + Send>>();
|
||||
let stderr_thread = if !stderr_tty {
|
||||
Some(std::thread::spawn(move || {
|
||||
if let Ok(mut cstderr) = stderr_recv.blocking_recv() {
|
||||
std::io::copy(&mut cstderr, &mut stderr.lock()).unwrap();
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
nix::sched::setns(
|
||||
open_file_read(chroot.join("proc/1/ns/pid"))?,
|
||||
CloneFlags::CLONE_NEWPID,
|
||||
@@ -428,32 +530,110 @@ pub fn exec(
|
||||
CloneFlags::CLONE_NEWIPC,
|
||||
)
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "set ipc ns"))?;
|
||||
let mut child = cmd
|
||||
.spawn()
|
||||
.map_err(color_eyre::eyre::Report::msg)
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "spawning child process"))?;
|
||||
send_pid.send(child.id() as i32).unwrap_or_default();
|
||||
stdin_send
|
||||
.send(child.stdin.take().unwrap())
|
||||
.unwrap_or_default();
|
||||
stdout_send
|
||||
.send(child.stdout.take().unwrap())
|
||||
.unwrap_or_default();
|
||||
stderr_send
|
||||
.send(child.stderr.take().unwrap())
|
||||
.unwrap_or_default();
|
||||
let exit = child
|
||||
.wait()
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "waiting on child process"))?;
|
||||
if let Some(code) = exit.code() {
|
||||
std::process::exit(code);
|
||||
} else if exit.success() {
|
||||
Ok(())
|
||||
|
||||
if tty {
|
||||
use pty_process::blocking as pty_process;
|
||||
let (pty, pts) = pty_process::open().with_kind(ErrorKind::Filesystem)?;
|
||||
let mut cmd = pty_process::Command::new("/usr/bin/start-cli");
|
||||
cmd = cmd.arg("subcontainer").arg("exec-command");
|
||||
if let Some(env) = env {
|
||||
cmd = cmd.arg("--env").arg(env);
|
||||
}
|
||||
if let Some(workdir) = workdir {
|
||||
cmd = cmd.arg("--workdir").arg(workdir);
|
||||
}
|
||||
if let Some(user) = user {
|
||||
cmd = cmd.arg("--user").arg(user);
|
||||
}
|
||||
cmd = cmd.arg(&chroot).args(&command);
|
||||
if !stderr_tty {
|
||||
cmd = cmd.stderr(Stdio::piped());
|
||||
}
|
||||
let mut child = cmd
|
||||
.spawn(pts)
|
||||
.map_err(color_eyre::eyre::Report::msg)
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "spawning child process"))?;
|
||||
send_pid.send(child.id() as i32).unwrap_or_default();
|
||||
if let Some(pty_size) = pty_size {
|
||||
let size = if let Some((x, y)) = pty_size.pixels {
|
||||
::pty_process::Size::new_with_pixel(pty_size.size.0, pty_size.size.1, x, y)
|
||||
} else {
|
||||
::pty_process::Size::new(pty_size.size.0, pty_size.size.1)
|
||||
};
|
||||
pty.resize(size).with_kind(ErrorKind::Filesystem)?;
|
||||
}
|
||||
let shared = ArcPty(Arc::new(pty));
|
||||
stdin_send
|
||||
.send(Box::new(shared.clone()))
|
||||
.unwrap_or_default();
|
||||
stdout_send
|
||||
.send(Box::new(shared.clone()))
|
||||
.unwrap_or_default();
|
||||
if let Some(stderr) = child.stderr.take() {
|
||||
stderr_send.send(Box::new(stderr)).unwrap_or_default();
|
||||
}
|
||||
let exit = child
|
||||
.wait()
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "waiting on child process"))?;
|
||||
stdout_thread.join().unwrap();
|
||||
stderr_thread.map(|t| t.join().unwrap());
|
||||
if let Some(code) = exit.code() {
|
||||
drop(raw);
|
||||
std::process::exit(code);
|
||||
} else if exit.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(
|
||||
color_eyre::eyre::Report::msg(exit),
|
||||
ErrorKind::Unknown,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Err(Error::new(
|
||||
color_eyre::eyre::Report::msg(exit),
|
||||
ErrorKind::Unknown,
|
||||
))
|
||||
let mut cmd = StdCommand::new("/usr/bin/start-cli");
|
||||
cmd.arg("subcontainer").arg("exec-command");
|
||||
if let Some(env) = env {
|
||||
cmd.arg("--env").arg(env);
|
||||
}
|
||||
if let Some(workdir) = workdir {
|
||||
cmd.arg("--workdir").arg(workdir);
|
||||
}
|
||||
if let Some(user) = user {
|
||||
cmd.arg("--user").arg(user);
|
||||
}
|
||||
cmd.arg(&chroot);
|
||||
cmd.args(&command);
|
||||
cmd.stdin(Stdio::piped());
|
||||
cmd.stdout(Stdio::piped());
|
||||
cmd.stderr(Stdio::piped());
|
||||
let mut child = cmd
|
||||
.spawn()
|
||||
.map_err(color_eyre::eyre::Report::msg)
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "spawning child process"))?;
|
||||
send_pid.send(child.id() as i32).unwrap_or_default();
|
||||
stdin_send
|
||||
.send(Box::new(child.stdin.take().unwrap()))
|
||||
.unwrap_or_default();
|
||||
stdout_send
|
||||
.send(Box::new(child.stdout.take().unwrap()))
|
||||
.unwrap_or_default();
|
||||
stderr_send
|
||||
.send(Box::new(child.stderr.take().unwrap()))
|
||||
.unwrap_or_default();
|
||||
let exit = child
|
||||
.wait()
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, "waiting on child process"))?;
|
||||
stdout_thread.join().unwrap();
|
||||
stderr_thread.map(|t| t.join().unwrap());
|
||||
if let Some(code) = exit.code() {
|
||||
std::process::exit(code);
|
||||
} else if exit.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(
|
||||
color_eyre::eyre::Report::msg(exit),
|
||||
ErrorKind::Unknown,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user