1use crate::builtins::run_builtin;
2use crate::command_data::{CommandWithArgs, Run};
3use crate::jobs::{Job, Jobs};
4use crate::parse::parse_line;
5use crate::platform::{FileDesc, Platform, Sys};
6use crate::signals::{install_sigint_handler, mask_signals};
7use std::{env, io};
8
9pub fn setup_shell_tty(shell_terminal: FileDesc) {
10 Sys::terminal_foreground(shell_terminal);
11
12 mask_signals();
13
14 if let Err(err) = Sys::set_self_pgroup() {
15 eprintln!("Couldn't put the shell in its own process group: {}\n", err)
16 }
17 if let Err(err) = Sys::grab_terminal(shell_terminal) {
19 eprintln!("Couldn't grab control of terminal: {err}");
20 return;
21 }
22
23 if !install_sigint_handler() {
24 std::process::exit(1)
25 }
26}
27
28fn finish_run(background: bool, mut job: Job, jobs: &mut Jobs) -> i32 {
36 job.mark_running();
37 let status = if !background {
38 if let Some(status) = Sys::wait_job(&mut job) {
39 unsafe {
40 env::set_var("LAST_STATUS", format!("{}", status));
41 }
42 status
43 } else {
44 unsafe {
45 env::set_var("LAST_STATUS", format!("{}", -66));
46 }
47 jobs.push_job(job);
48 -66
49 }
50 } else {
51 unsafe {
52 env::set_var("LAST_STATUS", format!("{}", 0));
53 }
54 let pid = if let Some(p) = job.pids().last() {
55 p.pid().try_into().unwrap_or(0)
56 } else {
57 0
58 };
59 jobs.push_job(job);
60 pid
61 };
62 jobs.restore_terminal();
63 status
64}
65
66fn run_command(
67 command: &CommandWithArgs,
68 jobs: &mut Jobs,
69 background: bool,
70 stealth: bool,
71) -> Result<i32, io::Error> {
72 Ok(if let Some(command_name) = command.command(jobs) {
73 let command_name = command_name?;
74 if let Some(init_alias_run) = jobs.remove_alias(command_name.to_string_lossy()) {
75 let mut alias_run = init_alias_run.clone();
77 for arg in command.args_iter() {
78 alias_run.push_arg_end(arg.clone());
79 }
80 if let Some(stdios) = command.stdios() {
81 alias_run.extend_redirs_end(stdios)
82 }
83 let r = run_job(&alias_run, jobs, background);
84 jobs.add_alias_run(command_name.to_string_lossy().to_string(), init_alias_run);
85 r?
86 } else {
87 let mut args = command.args_iter();
88 match run_builtin(&command_name, &mut args, jobs) {
89 Some(status) => status,
90 None => {
91 let mut job = jobs.new_job();
92 job.set_stealth(stealth);
93 match Sys::fork_exec(command, &mut job, jobs) {
94 Ok(()) => finish_run(background, job, jobs),
95 Err(err) => {
96 jobs.restore_terminal();
98 return Err(err);
99 }
100 }
101 }
102 }
103 }
104 } else {
105 0
106 })
107}
108
109pub fn run_job(run: &Run, jobs: &mut Jobs, force_background: bool) -> Result<i32, io::Error> {
110 let status = match run {
111 Run::Command(command) => run_command(command, jobs, force_background, force_background)?,
112 Run::BackgroundCommand(command) => run_command(command, jobs, true, false)?,
113 Run::Pipe(pipe) => {
114 let mut job = jobs.new_job();
115 job.set_stealth(force_background);
116 match run_pipe(&pipe[..], &mut job, jobs) {
117 Ok(background) => finish_run(force_background || background, job, jobs),
118 Err(err) => {
119 jobs.restore_terminal();
121 return Err(err);
122 }
123 }
124 }
125 Run::Sequence(seq) => {
126 let mut status = 0;
127 for r in seq {
128 status = run_job(r, jobs, force_background)?;
129 }
130 status
131 }
132 Run::And(seq) => {
133 let mut status = 0;
135 for r in seq {
136 status = run_job(r, jobs, force_background)?;
137 if status != 0 {
138 break;
139 }
140 }
141 status
142 }
143 Run::Or(seq) => {
144 let mut status = 0;
146 for r in seq {
147 status = run_job(r, jobs, force_background)?;
148 if status == 0 {
149 break;
150 }
151 }
152 status
153 }
154 Run::Subshell(sub_run) => {
155 let mut job = jobs.new_job();
156 job.set_stealth(force_background);
157 match Sys::fork_run(sub_run, &mut job, jobs) {
158 Ok(()) => finish_run(false, job, jobs),
159 Err(err) => {
160 jobs.restore_terminal();
162 return Err(err);
163 }
164 }
165 }
166 Run::Empty => 0,
167 };
168 Ok(status)
169}
170
171pub fn run_one_command(command: &str, jobs: &mut Jobs) -> Result<i32, io::Error> {
172 let commands = parse_line(jobs, command)?;
175
176 run_job(commands.commands(), jobs, false)
177}
178
179fn pipe_command(
180 command: &CommandWithArgs,
181 next_in: Option<FileDesc>,
182 next_out: Option<FileDesc>,
183 job: &mut Job,
184 jobs: &mut Jobs,
185) -> Result<(), io::Error> {
186 let mut command = command.clone();
187 if let Some(command_name) = command.command(jobs) {
188 let command_name = command_name?;
189 if let Some(mut alias_run) = jobs.get_alias(command_name.to_string_lossy()) {
190 alias_run.push_stdin_front(next_in);
191 alias_run.push_stdout_front(next_out);
192 for arg in command.args_iter() {
193 alias_run.push_arg_end(arg.clone());
194 }
195 if let Some(stdios) = command.stdios() {
196 alias_run.extend_redirs_end(stdios)
197 }
198 match alias_run {
199 Run::Command(command) | Run::BackgroundCommand(command) => {
200 Sys::fork_exec(&command, job, jobs)?;
201 }
202 _ => {
203 Sys::fork_run(&alias_run, job, jobs)?;
204 }
205 }
206 } else {
207 command.push_stdin_front(next_in);
208 command.push_stdout_front(next_out);
209 Sys::fork_exec(&command, job, jobs)?;
210 }
211 }
212 Ok(())
213}
214
215fn run_pipe(new_job: &[Run], job: &mut Job, jobs: &mut Jobs) -> Result<bool, io::Error> {
216 let progs = new_job.len();
217 let (p_in, p_out) = Sys::anon_pipe()?;
218 let mut next_in = Some(p_in);
219 let mut next_out = None;
220 let mut upcoming_out = p_out;
221 let mut background = false;
222 for (i, program) in new_job.iter().rev().enumerate() {
223 match program {
224 Run::Command(command) => {
225 pipe_command(command, next_in, next_out, job, jobs)?;
226 }
227 Run::BackgroundCommand(command) => {
228 pipe_command(command, next_in, next_out, job, jobs)?;
229 if i == 0 {
230 background = true;
231 }
232 }
233 Run::Subshell(_) => {
234 let mut program = program.clone();
235 program.push_stdin_front(next_in);
236 program.push_stdout_front(next_out);
237 if let Run::Subshell(sub_run) = &mut program {
238 match Sys::fork_run(&*sub_run, job, jobs) {
239 Ok(()) => {
240 jobs.restore_terminal();
241 }
242 Err(err) => {
243 jobs.restore_terminal();
245 return Err(err);
246 }
247 }
248 }
249 }
250 Run::Pipe(_) | Run::Sequence(_) | Run::And(_) | Run::Or(_) => {
251 let mut program = program.clone();
253 program.push_stdin_front(next_in);
254 program.push_stdout_front(next_out);
255 run_job(&program, jobs, true)?;
256 }
257 Run::Empty => {}
258 }
259 next_out = Some(upcoming_out);
260 if i < (progs - 1) {
261 let (p_in, p_out) = Sys::anon_pipe()?;
262 upcoming_out = p_out;
263 next_in = Some(p_in);
264 } else {
265 next_in = None;
266 }
267 }
268 if job.is_empty() {
269 Err(io::Error::other("no processes started"))
270 } else {
271 job.reverse();
272 Ok(background)
273 }
274}