Skip to content

Commit

Permalink
修复执行前台命令时未设置前台进程的错误 (#51)
Browse files Browse the repository at this point in the history
* 修复前台命令未设置前台进程的问题

* 修复exec命令未设置前台进程的问题

* 完善pipeline的执行逻辑
  • Loading branch information
MemoryShore authored Oct 30, 2024
1 parent 0b5cf83 commit cb835e0
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 21 deletions.
56 changes: 45 additions & 11 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -479,9 +479,8 @@ impl Pipeline {

// 如果之前没有出错,执行命令
if err.is_none() {
match f(&cmd.args) {
Ok(_) => err = None,
Err(err_type) => err = Some(err_type),
if let Err(err_type) = f(&cmd.args) {
err = Some(err_type);
}
}

Expand All @@ -495,16 +494,38 @@ impl Pipeline {
libc::dup2(old_stdout, libc::STDOUT_FILENO);
}
}
} else if child_fd < 0 {
err = Some(ExecuteErrorType::ExecuteFailed)
}

// 后台命令且当前进程为父进程
if self.backend && !child_fd == 0 {
err = match unsafe { libc::waitpid(child_fd, std::ptr::null_mut(), 0) } {
-1 => Some(ExecuteErrorType::ExecuteFailed),
_ => None,
if self.backend {
// 当前为后台进程,退出当前进程
std::process::exit(if err.is_none() { 0 } else { 1 });
}
} else if child_fd > 0 {
// 当前进程为父进程
unsafe {
// 设置前台进程
libc::tcsetpgrp(libc::STDIN_FILENO, child_fd);

let mut status = 0;
err = match libc::waitpid(child_fd, &mut status, 0) {
-1 => Some(ExecuteErrorType::ExecuteFailed),
_ => None,
};

if status != 0 {
if libc::WIFEXITED(status) {
if libc::WEXITSTATUS(status) != 0 {
err = Some(ExecuteErrorType::ExitWithCode(status));
}
} else if libc::WIFSIGNALED(status) {
err = Some(ExecuteErrorType::ProcessTerminated);
}
}

// 还原前台进程
libc::tcsetpgrp(libc::STDIN_FILENO, std::process::id() as i32);
}
} else {
err = Some(ExecuteErrorType::ExecuteFailed)
}
}
};
Expand Down Expand Up @@ -586,6 +607,11 @@ impl Pipeline {

// println!("exec command: {child_command:#?}");

unsafe {
// 设置前台进程
libc::tcsetpgrp(libc::STDIN_FILENO, child.id() as i32);
};

match child.wait() {
Ok(exit_status) => match exit_status.code() {
Some(exit_code) => {
Expand All @@ -600,6 +626,14 @@ impl Pipeline {
Err(_) => err = Some(ExecuteErrorType::ExecuteFailed),
};

// 还原前台进程
unsafe {
libc::tcsetpgrp(
libc::STDIN_FILENO,
std::process::id() as i32,
);
}

children.push(child);
}

Expand Down
43 changes: 33 additions & 10 deletions src/shell/command/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,24 +93,47 @@ impl BuildInCmd {
which::which(name).map_err(|_| ExecuteErrorType::CommandNotFound)
}?;

let pgrp = unsafe { libc::tcgetpgrp(libc::STDIN_FILENO) };

// 如果当前终端的前台进程等于当前进程,则设置前台进程
let run_foreground = if pgrp >= 0 {
if pgrp as u32 == std::process::id() {
true
} else {
false
}
} else {
false
};

let mut err: Option<ExecuteErrorType> = None;

match std::process::Command::new(real_path)
.args(args)
.current_dir(EnvManager::current_dir())
.spawn()
{
Ok(mut child) => match child.wait() {
Ok(exit_status) => match exit_status.code() {
Some(exit_code) => {
if exit_code != 0 {
err = Some(ExecuteErrorType::ExitWithCode(exit_code));
Ok(mut child) => {
if run_foreground {
unsafe { libc::tcsetpgrp(libc::STDIN_FILENO, child.id() as i32) };
}

match child.wait() {
Ok(exit_status) => match exit_status.code() {
Some(exit_code) => {
if exit_code != 0 {
err = Some(ExecuteErrorType::ExitWithCode(exit_code));
}
}
}
None => err = Some(ExecuteErrorType::ProcessTerminated),
},
Err(_) => err = Some(ExecuteErrorType::ExecuteFailed),
},
None => err = Some(ExecuteErrorType::ProcessTerminated),
},
Err(_) => err = Some(ExecuteErrorType::ExecuteFailed),
}

if run_foreground {
unsafe { libc::tcsetpgrp(libc::STDIN_FILENO, std::process::id() as i32) };
}
}
Err(_) => todo!(),
};
return if let Some(err) = err {
Expand Down

0 comments on commit cb835e0

Please sign in to comment.