implemented PIPESTATUS variable from bash. puts all exit codes from last pipeline into an array.
This commit is contained in:
42
src/jobs.rs
42
src/jobs.rs
@@ -1,3 +1,5 @@
|
|||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use ariadne::Fmt;
|
use ariadne::Fmt;
|
||||||
use scopeguard::defer;
|
use scopeguard::defer;
|
||||||
use yansi::Color;
|
use yansi::Color;
|
||||||
@@ -10,7 +12,7 @@ use crate::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
procio::{IoMode, borrow_fd},
|
procio::{IoMode, borrow_fd},
|
||||||
signal::{disable_reaping, enable_reaping},
|
signal::{disable_reaping, enable_reaping},
|
||||||
state::{self, ShellParam, set_status, write_jobs, write_vars},
|
state::{self, ShellParam, Var, VarFlags, VarKind, set_status, write_jobs, write_vars},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const SIG_EXIT_OFFSET: i32 = 128;
|
pub const SIG_EXIT_OFFSET: i32 = 128;
|
||||||
@@ -596,6 +598,26 @@ impl Job {
|
|||||||
.map(|chld| chld.stat())
|
.map(|chld| chld.stat())
|
||||||
.collect::<Vec<WtStat>>()
|
.collect::<Vec<WtStat>>()
|
||||||
}
|
}
|
||||||
|
pub fn pipe_status(stats: &[WtStat]) -> Option<Vec<i32>> {
|
||||||
|
if stats.iter()
|
||||||
|
.any(|stat| matches!(stat, WtStat::StillAlive | WtStat::Continued(_) | WtStat::PtraceSyscall(_)))
|
||||||
|
|| stats.len() <= 1 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(stats.iter()
|
||||||
|
.map(|stat| {
|
||||||
|
match stat {
|
||||||
|
WtStat::Exited(_, code) => *code,
|
||||||
|
WtStat::Signaled(_, signal, _) => SIG_EXIT_OFFSET + *signal as i32,
|
||||||
|
WtStat::Stopped(_, signal) => SIG_EXIT_OFFSET + *signal as i32,
|
||||||
|
WtStat::PtraceEvent(_, signal, _) => SIG_EXIT_OFFSET + *signal as i32,
|
||||||
|
WtStat::PtraceSyscall(_) |
|
||||||
|
WtStat::Continued(_) |
|
||||||
|
WtStat::StillAlive => unreachable!()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
pub fn get_pids(&self) -> Vec<Pid> {
|
pub fn get_pids(&self) -> Vec<Pid> {
|
||||||
self
|
self
|
||||||
.children
|
.children
|
||||||
@@ -839,22 +861,30 @@ pub fn wait_fg(job: Job, interactive: bool) -> ShResult<()> {
|
|||||||
enable_reaping();
|
enable_reaping();
|
||||||
}
|
}
|
||||||
let statuses = write_jobs(|j| j.new_fg(job))?;
|
let statuses = write_jobs(|j| j.new_fg(job))?;
|
||||||
for status in statuses {
|
for status in &statuses {
|
||||||
code = code_from_status(&status).unwrap_or(0);
|
code = code_from_status(status).unwrap_or(0);
|
||||||
match status {
|
match status {
|
||||||
WtStat::Stopped(_, _) => {
|
WtStat::Stopped(_, _) => {
|
||||||
was_stopped = true;
|
was_stopped = true;
|
||||||
write_jobs(|j| j.fg_to_bg(status))?;
|
write_jobs(|j| j.fg_to_bg(*status))?;
|
||||||
}
|
}
|
||||||
WtStat::Signaled(_, sig, _) => {
|
WtStat::Signaled(_, sig, _) => {
|
||||||
if sig == Signal::SIGTSTP {
|
if *sig == Signal::SIGTSTP {
|
||||||
was_stopped = true;
|
was_stopped = true;
|
||||||
write_jobs(|j| j.fg_to_bg(status))?;
|
write_jobs(|j| j.fg_to_bg(*status))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => { /* Do nothing */ }
|
_ => { /* Do nothing */ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(pipe_status) = Job::pipe_status(&statuses) {
|
||||||
|
let pipe_status = pipe_status
|
||||||
|
.into_iter()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.collect::<VecDeque<String>>();
|
||||||
|
|
||||||
|
write_vars(|v| v.set_var("PIPESTATUS", VarKind::Arr(pipe_status), VarFlags::NONE))?;
|
||||||
|
}
|
||||||
// If job wasn't stopped (moved to bg), clear the fg slot
|
// If job wasn't stopped (moved to bg), clear the fg slot
|
||||||
if !was_stopped {
|
if !was_stopped {
|
||||||
write_jobs(|j| {
|
write_jobs(|j| {
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
use std::sync::atomic::{AtomicBool, AtomicI32, AtomicU64, Ordering};
|
use std::{collections::VecDeque, sync::atomic::{AtomicBool, AtomicI32, AtomicU64, Ordering}};
|
||||||
|
|
||||||
use nix::sys::signal::{SaFlags, SigAction, sigaction};
|
use nix::sys::signal::{SaFlags, SigAction, sigaction};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
builtin::trap::TrapTarget,
|
builtin::trap::TrapTarget,
|
||||||
jobs::{JobCmdFlags, JobID, take_term},
|
jobs::{Job, JobCmdFlags, JobID, take_term},
|
||||||
libsh::error::{ShErr, ShErrKind, ShResult},
|
libsh::error::{ShErr, ShErrKind, ShResult},
|
||||||
parse::execute::exec_input,
|
parse::execute::exec_input,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
state::{AutoCmd, AutoCmdKind, read_jobs, read_logic, write_jobs, write_meta},
|
state::{AutoCmd, AutoCmdKind, VarFlags, VarKind, read_jobs, read_logic, write_jobs, write_meta, write_vars},
|
||||||
};
|
};
|
||||||
|
|
||||||
static SIGNALS: AtomicU64 = AtomicU64::new(0);
|
static SIGNALS: AtomicU64 = AtomicU64::new(0);
|
||||||
@@ -316,6 +316,16 @@ pub fn child_exited(pid: Pid, status: WtStat) -> ShResult<()> {
|
|||||||
let result = read_jobs(|j| j.query(JobID::Pgid(pgid)).cloned());
|
let result = read_jobs(|j| j.query(JobID::Pgid(pgid)).cloned());
|
||||||
if let Some(job) = result {
|
if let Some(job) = result {
|
||||||
let job_complete_msg = job.display(&job_order, JobCmdFlags::PIDS).to_string();
|
let job_complete_msg = job.display(&job_order, JobCmdFlags::PIDS).to_string();
|
||||||
|
let statuses = job.get_stats();
|
||||||
|
|
||||||
|
if let Some(pipe_status) = Job::pipe_status(&statuses) {
|
||||||
|
let pipe_status = pipe_status
|
||||||
|
.into_iter()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.collect::<VecDeque<String>>();
|
||||||
|
|
||||||
|
write_vars(|v| v.set_var("PIPESTATUS", VarKind::Arr(pipe_status), VarFlags::NONE))?;
|
||||||
|
}
|
||||||
|
|
||||||
let post_job_hooks = read_logic(|l| l.get_autocmds(AutoCmdKind::OnJobFinish));
|
let post_job_hooks = read_logic(|l| l.get_autocmds(AutoCmdKind::OnJobFinish));
|
||||||
for cmd in post_job_hooks {
|
for cmd in post_job_hooks {
|
||||||
|
|||||||
Reference in New Issue
Block a user