Skip to content

Commit 524b874

Browse files
committed
sh: wait before putting pipeline in the foreground
1 parent d15e7d8 commit 524b874

File tree

1 file changed

+20
-7
lines changed

1 file changed

+20
-7
lines changed

sh/src/shell/mod.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ use crate::wordexp::{expand_word, expand_word_to_string, word_to_pattern};
3535
use nix::errno::Errno;
3636
use nix::libc;
3737
use nix::sys::wait::{WaitPidFlag, WaitStatus};
38-
use nix::unistd::{getcwd, getpgrp, getpid, getppid, setpgid, ForkResult, Pid};
38+
use nix::unistd::{
39+
getcwd, getgid, getpgid, getpgrp, getpid, getppid, setpgid, tcsetpgrp, ForkResult, Pid,
40+
};
3941
use std::collections::HashMap;
4042
use std::ffi::{CString, OsString};
4143
use std::fmt::{Display, Formatter};
@@ -729,17 +731,17 @@ impl Shell {
729731
match fork()? {
730732
ForkResult::Child => {
731733
self.become_subshell();
732-
setpgid(Pid::from_raw(0), Pid::from_raw(0))
733-
.expect("failed to create new process group for pipeline");
734+
// this should never fail as both arguments are valid
735+
setpgid(Pid::from_raw(0), Pid::from_raw(0)).unwrap();
734736
let pipeline_pgid = getpgrp();
735737

736738
let mut current_stdin = libc::STDIN_FILENO;
737739
for command in pipeline.commands.head() {
738740
let (read_pipe, write_pipe) = pipe()?;
739741
match fork()? {
740742
ForkResult::Child => {
741-
setpgid(Pid::from_raw(0), pipeline_pgid)
742-
.expect("failed to set pipeline pgid");
743+
// should never fail as `pipeline_pgid` is a valid process group
744+
setpgid(Pid::from_raw(0), pipeline_pgid).unwrap();
743745
drop(read_pipe);
744746
dup2(current_stdin, libc::STDIN_FILENO)?;
745747
dup2(write_pipe.as_raw_fd(), libc::STDOUT_FILENO)?;
@@ -764,9 +766,20 @@ impl Shell {
764766
}
765767
ForkResult::Parent { child } => {
766768
if is_process_in_foreground() {
767-
nix::unistd::tcsetpgrp(io::stdin().as_fd(), child).unwrap();
769+
// unwrap should never fail as child is a valid process id and in the
770+
// same session as the shell process
771+
while getpgid(Some(child)).unwrap().as_raw() as u32 == getgid().as_raw() {
772+
// loop until child is process group leader
773+
self.update_global_state();
774+
std::thread::sleep(Duration::from_millis(16));
775+
}
776+
// should never fail as stdin is a valid file descriptor and
777+
// child is a valid group id and is in the same session
778+
// as the shell process
779+
tcsetpgrp(io::stdin().as_fd(), child).unwrap();
768780
pipeline_exit_status = self.wait_child_process(child)?;
769-
nix::unistd::tcsetpgrp(io::stdin().as_fd(), getpgrp()).unwrap();
781+
// should never fail
782+
tcsetpgrp(io::stdin().as_fd(), getpgrp()).unwrap();
770783
} else {
771784
pipeline_exit_status = self.wait_child_process(child)?;
772785
}

0 commit comments

Comments
 (0)