1 // Provides the "linkage" between an ast and actual execution structures (job_t, etc.)
2 #include "config.h" // IWYU pragma: keep
3
4 #include "parse_execution.h"
5
6 #include <errno.h>
7 #include <stdarg.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <termios.h>
11 #include <unistd.h>
12 #include <wctype.h>
13
14 #include <algorithm>
15 #include <cwchar>
16 #include <memory>
17 #include <string>
18 #include <type_traits>
19 #include <vector>
20
21 #include "ast.h"
22 #include "builtin.h"
23 #include "builtin_function.h"
24 #include "common.h"
25 #include "complete.h"
26 #include "env.h"
27 #include "event.h"
28 #include "exec.h"
29 #include "expand.h"
30 #include "flog.h"
31 #include "function.h"
32 #include "io.h"
33 #include "job_group.h"
34 #include "maybe.h"
35 #include "parse_constants.h"
36 #include "parse_util.h"
37 #include "parser.h"
38 #include "path.h"
39 #include "proc.h"
40 #include "reader.h"
41 #include "timer.h"
42 #include "tokenizer.h"
43 #include "trace.h"
44 #include "util.h"
45 #include "wildcard.h"
46 #include "wutil.h"
47
48 /// These are the specific statement types that support redirections.
type_is_redirectable_block(ast::type_t type)49 static constexpr bool type_is_redirectable_block(ast::type_t type) {
50 using t = ast::type_t;
51 return type == t::block_statement || type == t::if_statement || type == t::switch_statement;
52 }
53
specific_statement_type_is_redirectable_block(const ast::node_t & node)54 static bool specific_statement_type_is_redirectable_block(const ast::node_t &node) {
55 return type_is_redirectable_block(node.type);
56 }
57
58 /// Get the name of a redirectable block, for profiling purposes.
profiling_cmd_name_for_redirectable_block(const ast::node_t & node,const parsed_source_t & pstree)59 static wcstring profiling_cmd_name_for_redirectable_block(const ast::node_t &node,
60 const parsed_source_t &pstree) {
61 using namespace ast;
62 assert(specific_statement_type_is_redirectable_block(node));
63
64 auto source_range = node.try_source_range();
65 assert(source_range.has_value() && "No source range for block");
66
67 size_t src_end = 0;
68 switch (node.type) {
69 case type_t::block_statement: {
70 const node_t *block_header = node.as<block_statement_t>()->header.get();
71 switch (block_header->type) {
72 case type_t::for_header:
73 src_end = block_header->as<for_header_t>()->semi_nl.source_range().start;
74 break;
75
76 case type_t::while_header:
77 src_end = block_header->as<while_header_t>()->condition.source_range().end();
78 break;
79
80 case type_t::function_header:
81 src_end = block_header->as<function_header_t>()->semi_nl.source_range().start;
82 break;
83
84 case type_t::begin_header:
85 src_end = block_header->as<begin_header_t>()->kw_begin.source_range().end();
86 break;
87
88 default:
89 DIE("Unexpected block header type");
90 }
91 } break;
92
93 case type_t::if_statement:
94 src_end = node.as<if_statement_t>()->if_clause.condition.job.source_range().end();
95 break;
96
97 case type_t::switch_statement:
98 src_end = node.as<switch_statement_t>()->semi_nl.source_range().start;
99 break;
100
101 default:
102 DIE("Not a redirectable block type");
103 break;
104 }
105
106 assert(src_end >= source_range->start && "Invalid source end");
107
108 // Get the source for the block, and cut it at the next statement terminator.
109 wcstring result = pstree.src.substr(source_range->start, src_end - source_range->start);
110 result.append(L"...");
111 return result;
112 }
113
114 /// Get a redirection from stderr to stdout (i.e. 2>&1).
get_stderr_merge()115 static redirection_spec_t get_stderr_merge() {
116 const wchar_t *stdout_fileno_str = L"1";
117 return redirection_spec_t{STDERR_FILENO, redirection_mode_t::fd, stdout_fileno_str};
118 }
119
parse_execution_context_t(parsed_source_ref_t pstree,const operation_context_t & ctx,cancellation_group_ref_t cancel_group,io_chain_t block_io)120 parse_execution_context_t::parse_execution_context_t(parsed_source_ref_t pstree,
121 const operation_context_t &ctx,
122 cancellation_group_ref_t cancel_group,
123 io_chain_t block_io)
124 : pstree(std::move(pstree)),
125 parser(ctx.parser.get()),
126 ctx(ctx),
127 cancel_group(std::move(cancel_group)),
128 block_io(std::move(block_io)) {}
129
130 // Utilities
131
get_source(const ast::node_t & node) const132 wcstring parse_execution_context_t::get_source(const ast::node_t &node) const {
133 return node.source(pstree->src);
134 }
135
136 const ast::decorated_statement_t *
infinite_recursive_statement_in_job_list(const ast::job_list_t & jobs,wcstring * out_func_name) const137 parse_execution_context_t::infinite_recursive_statement_in_job_list(const ast::job_list_t &jobs,
138 wcstring *out_func_name) const {
139 // This is a bit fragile. It is a test to see if we are inside of function call, but not inside
140 // a block in that function call. If, in the future, the rules for what block scopes are pushed
141 // on function invocation changes, then this check will break.
142 const block_t *current = parser->block_at_index(0), *parent = parser->block_at_index(1);
143 bool is_within_function_call =
144 (current && parent && current->type() == block_type_t::top && parent->is_function_call());
145 if (!is_within_function_call) {
146 return nullptr;
147 }
148
149 // Get the function name of the immediate block.
150 const wcstring &forbidden_function_name = parent->function_name;
151
152 // Get the first job in the job list.
153 const ast::job_conjunction_t *jc = jobs.at(0);
154 if (!jc) return nullptr;
155 const ast::job_t *job = &jc->job;
156
157 // Helper to return if a statement is infinitely recursive in this function.
158 auto statement_recurses =
159 [&](const ast::statement_t &stat) -> const ast::decorated_statement_t * {
160 // Ignore non-decorated statements like `if`, etc.
161 const ast::decorated_statement_t *dc =
162 stat.contents.contents->try_as<ast::decorated_statement_t>();
163 if (!dc) return nullptr;
164
165 // Ignore statements with decorations like 'builtin' or 'command', since those
166 // are not infinite recursion. In particular that is what enables 'wrapper functions'.
167 if (dc->decoration() != statement_decoration_t::none) return nullptr;
168
169 // Check the command.
170 wcstring cmd = dc->command.source(pstree->src);
171 bool forbidden =
172 !cmd.empty() &&
173 expand_one(cmd, {expand_flag::skip_cmdsubst, expand_flag::skip_variables}, ctx) &&
174 cmd == forbidden_function_name;
175 return forbidden ? dc : nullptr;
176 };
177
178 const ast::decorated_statement_t *infinite_recursive_statement = nullptr;
179
180 // Check main statement.
181 infinite_recursive_statement = statement_recurses(jc->job.statement);
182
183 // Check piped remainder.
184 if (!infinite_recursive_statement) {
185 for (const ast::job_continuation_t &c : job->continuation) {
186 if (const auto *s = statement_recurses(c.statement)) {
187 infinite_recursive_statement = s;
188 break;
189 }
190 }
191 }
192
193 if (infinite_recursive_statement && out_func_name) {
194 *out_func_name = forbidden_function_name;
195 }
196 // may be null
197 return infinite_recursive_statement;
198 }
199
process_type_for_command(const ast::decorated_statement_t & statement,const wcstring & cmd) const200 process_type_t parse_execution_context_t::process_type_for_command(
201 const ast::decorated_statement_t &statement, const wcstring &cmd) const {
202 enum process_type_t process_type = process_type_t::external;
203
204 // Determine the process type, which depends on the statement decoration (command, builtin,
205 // etc).
206 switch (statement.decoration()) {
207 case statement_decoration_t::exec:
208 process_type = process_type_t::exec;
209 break;
210 case statement_decoration_t::command:
211 process_type = process_type_t::external;
212 break;
213 case statement_decoration_t::builtin:
214 process_type = process_type_t::builtin;
215 break;
216 case statement_decoration_t::none:
217 if (function_exists(cmd, *parser)) {
218 process_type = process_type_t::function;
219 } else if (builtin_exists(cmd)) {
220 process_type = process_type_t::builtin;
221 } else {
222 process_type = process_type_t::external;
223 }
224 break;
225 }
226
227 return process_type;
228 }
229
check_end_execution() const230 maybe_t<end_execution_reason_t> parse_execution_context_t::check_end_execution() const {
231 if (ctx.check_cancel() || check_cancel_from_fish_signal()) {
232 return end_execution_reason_t::cancelled;
233 }
234 const auto &ld = parser->libdata();
235 if (ld.exit_current_script) {
236 return end_execution_reason_t::cancelled;
237 }
238 if (ld.returning) {
239 return end_execution_reason_t::control_flow;
240 }
241 if (ld.loop_status != loop_status_t::normals) {
242 return end_execution_reason_t::control_flow;
243 }
244 return none();
245 }
246
247 /// Return whether the job contains a single statement, of block type, with no redirections.
job_is_simple_block(const ast::job_t & job) const248 bool parse_execution_context_t::job_is_simple_block(const ast::job_t &job) const {
249 using namespace ast;
250 // Must be no pipes.
251 if (!job.continuation.empty()) {
252 return false;
253 }
254
255 // Helper to check if an argument_or_redirection_list_t has no redirections.
256 auto no_redirs = [](const argument_or_redirection_list_t &list) -> bool {
257 for (const argument_or_redirection_t &val : list) {
258 if (val.is_redirection()) return false;
259 }
260 return true;
261 };
262
263 // Check if we're a block statement with redirections. We do it this obnoxious way to preserve
264 // type safety (in case we add more specific statement types).
265 const node_t &ss = *job.statement.contents.contents;
266 switch (ss.type) {
267 case type_t::block_statement:
268 return no_redirs(ss.as<block_statement_t>()->args_or_redirs);
269 case type_t::switch_statement:
270 return no_redirs(ss.as<switch_statement_t>()->args_or_redirs);
271 case type_t::if_statement:
272 return no_redirs(ss.as<if_statement_t>()->args_or_redirs);
273 case type_t::not_statement:
274 case type_t::decorated_statement:
275 // not block statements
276 return false;
277 default:
278 assert(0 && "Unexpected child block type");
279 return false;
280 }
281 }
282
run_if_statement(const ast::if_statement_t & statement,const block_t * associated_block)283 end_execution_reason_t parse_execution_context_t::run_if_statement(
284 const ast::if_statement_t &statement, const block_t *associated_block) {
285 using namespace ast;
286 using job_list_t = ast::job_list_t;
287 end_execution_reason_t result = end_execution_reason_t::ok;
288
289 // We have a sequence of if clauses, with a final else, resulting in a single job list that we
290 // execute.
291 const job_list_t *job_list_to_execute = nullptr;
292 const if_clause_t *if_clause = &statement.if_clause;
293
294 // Index of the *next* elseif_clause to test.
295 const elseif_clause_list_t &elseif_clauses = statement.elseif_clauses;
296 size_t next_elseif_idx = 0;
297
298 // We start with the 'if'.
299 trace_if_enabled(*parser, L"if");
300
301 for (;;) {
302 if (auto ret = check_end_execution()) {
303 result = *ret;
304 break;
305 }
306
307 // An if condition has a job and a "tail" of andor jobs, e.g. "foo ; and bar; or baz".
308 // Check the condition and the tail. We treat end_execution_reason_t::error here as failure,
309 // in accordance with historic behavior.
310 end_execution_reason_t cond_ret =
311 run_job_conjunction(if_clause->condition, associated_block);
312 if (cond_ret == end_execution_reason_t::ok) {
313 cond_ret = run_job_list(if_clause->andor_tail, associated_block);
314 }
315 const bool take_branch =
316 (cond_ret == end_execution_reason_t::ok) && parser->get_last_status() == EXIT_SUCCESS;
317
318 if (take_branch) {
319 // Condition succeeded.
320 job_list_to_execute = &if_clause->body;
321 break;
322 }
323
324 // See if we have an elseif.
325 const auto *elseif_clause = elseif_clauses.at(next_elseif_idx++);
326 if (elseif_clause) {
327 trace_if_enabled(*parser, L"else if");
328 if_clause = &elseif_clause->if_clause;
329 } else {
330 break;
331 }
332 }
333
334 if (!job_list_to_execute) {
335 // our ifs and elseifs failed.
336 // Check our else body.
337 if (statement.else_clause) {
338 trace_if_enabled(*parser, L"else");
339 job_list_to_execute = &statement.else_clause->body;
340 }
341 }
342
343 if (!job_list_to_execute) {
344 // 'if' condition failed, no else clause, return 0, we're done.
345 // No job list means no successful conditions, so return 0 (issue #1443).
346 parser->set_last_statuses(statuses_t::just(STATUS_CMD_OK));
347 } else {
348 // Execute the job list we got.
349 block_t *ib = parser->push_block(block_t::if_block());
350 run_job_list(*job_list_to_execute, ib);
351 if (auto ret = check_end_execution()) {
352 result = *ret;
353 }
354 parser->pop_block(ib);
355 }
356 trace_if_enabled(*parser, L"end if");
357
358 // It's possible there's a last-minute cancellation (issue #1297).
359 if (auto ret = check_end_execution()) {
360 result = *ret;
361 }
362
363 // Otherwise, take the exit status of the job list. Reversal of issue #1061.
364 return result;
365 }
366
run_begin_statement(const ast::job_list_t & contents)367 end_execution_reason_t parse_execution_context_t::run_begin_statement(
368 const ast::job_list_t &contents) {
369 // Basic begin/end block. Push a scope block, run jobs, pop it
370 trace_if_enabled(*parser, L"begin");
371 block_t *sb = parser->push_block(block_t::scope_block(block_type_t::begin));
372 end_execution_reason_t ret = run_job_list(contents, sb);
373 parser->pop_block(sb);
374 trace_if_enabled(*parser, L"end begin");
375 return ret;
376 }
377
378 // Define a function.
run_function_statement(const ast::block_statement_t & statement,const ast::function_header_t & header)379 end_execution_reason_t parse_execution_context_t::run_function_statement(
380 const ast::block_statement_t &statement, const ast::function_header_t &header) {
381 using namespace ast;
382 // Get arguments.
383 wcstring_list_t arguments;
384 ast_args_list_t arg_nodes = get_argument_nodes(header.args);
385 arg_nodes.insert(arg_nodes.begin(), &header.first_arg);
386 end_execution_reason_t result =
387 this->expand_arguments_from_nodes(arg_nodes, &arguments, failglob);
388
389 if (result != end_execution_reason_t::ok) {
390 return result;
391 }
392 trace_if_enabled(*parser, L"function", arguments);
393 null_output_stream_t outs;
394 string_output_stream_t errs;
395 io_streams_t streams(outs, errs);
396 int err_code = 0;
397 maybe_t<int> err = builtin_function(*parser, streams, arguments, pstree, statement);
398 if (err) {
399 err_code = err.value();
400 parser->libdata().status_count++;
401 parser->set_last_statuses(statuses_t::just(err_code));
402 }
403
404 const wcstring &errtext = errs.contents();
405 if (!errtext.empty()) {
406 return this->report_error(err_code, header, L"%ls", errtext.c_str());
407 }
408 return result;
409 }
410
run_block_statement(const ast::block_statement_t & statement,const block_t * associated_block)411 end_execution_reason_t parse_execution_context_t::run_block_statement(
412 const ast::block_statement_t &statement, const block_t *associated_block) {
413 const ast::node_t &bh = *statement.header.contents;
414 const ast::job_list_t &contents = statement.jobs;
415 end_execution_reason_t ret = end_execution_reason_t::ok;
416 if (const auto *fh = bh.try_as<ast::for_header_t>()) {
417 ret = run_for_statement(*fh, contents);
418 } else if (const auto *wh = bh.try_as<ast::while_header_t>()) {
419 ret = run_while_statement(*wh, contents, associated_block);
420 } else if (const auto *fh = bh.try_as<ast::function_header_t>()) {
421 ret = run_function_statement(statement, *fh);
422 } else if (bh.try_as<ast::begin_header_t>()) {
423 ret = run_begin_statement(contents);
424 } else {
425 FLOGF(error, L"Unexpected block header: %ls\n", bh.describe().c_str());
426 PARSER_DIE();
427 }
428 return ret;
429 }
430
run_for_statement(const ast::for_header_t & header,const ast::job_list_t & block_contents)431 end_execution_reason_t parse_execution_context_t::run_for_statement(
432 const ast::for_header_t &header, const ast::job_list_t &block_contents) {
433 // Get the variable name: `for var_name in ...`. We expand the variable name. It better result
434 // in just one.
435 wcstring for_var_name = header.var_name.source(get_source());
436 if (!expand_one(for_var_name, expand_flags_t{}, ctx)) {
437 return report_error(STATUS_EXPAND_ERROR, header.var_name,
438 FAILED_EXPANSION_VARIABLE_NAME_ERR_MSG, for_var_name.c_str());
439 }
440
441 // Get the contents to iterate over.
442 wcstring_list_t arguments;
443 ast_args_list_t arg_nodes = get_argument_nodes(header.args);
444 end_execution_reason_t ret = this->expand_arguments_from_nodes(arg_nodes, &arguments, nullglob);
445 if (ret != end_execution_reason_t::ok) {
446 return ret;
447 }
448
449 auto var = parser->vars().get(for_var_name, ENV_DEFAULT);
450 if (var && var->read_only()) {
451 return report_error(STATUS_INVALID_ARGS, header.var_name,
452 L"You cannot use read-only variable '%ls' in a for loop",
453 for_var_name.c_str());
454 }
455 int retval;
456 if (var) {
457 retval = parser->set_var_and_fire(for_var_name, ENV_LOCAL | ENV_USER, var->as_list());
458 } else {
459 retval = parser->set_empty_var_and_fire(for_var_name, ENV_LOCAL | ENV_USER);
460 }
461 assert(retval == ENV_OK);
462
463 if (!valid_var_name(for_var_name)) {
464 return report_error(STATUS_INVALID_ARGS, header.var_name, BUILTIN_ERR_VARNAME, L"for",
465 for_var_name.c_str());
466 }
467
468 trace_if_enabled(*parser, L"for", arguments);
469 block_t *fb = parser->push_block(block_t::for_block());
470
471 // Now drive the for loop.
472 for (const wcstring &val : arguments) {
473 if (auto reason = check_end_execution()) {
474 ret = *reason;
475 break;
476 }
477
478 int retval = parser->set_var_and_fire(for_var_name, ENV_DEFAULT | ENV_USER, val);
479 assert(retval == ENV_OK && "for loop variable should have been successfully set");
480 (void)retval;
481
482 auto &ld = parser->libdata();
483 ld.loop_status = loop_status_t::normals;
484 this->run_job_list(block_contents, fb);
485
486 if (check_end_execution() == end_execution_reason_t::control_flow) {
487 // Handle break or continue.
488 bool do_break = (ld.loop_status == loop_status_t::breaks);
489 ld.loop_status = loop_status_t::normals;
490 if (do_break) {
491 break;
492 }
493 }
494 }
495
496 parser->pop_block(fb);
497 trace_if_enabled(*parser, L"end for");
498 return ret;
499 }
500
run_switch_statement(const ast::switch_statement_t & statement)501 end_execution_reason_t parse_execution_context_t::run_switch_statement(
502 const ast::switch_statement_t &statement) {
503 // Get the switch variable.
504 const wcstring switch_value = get_source(statement.argument);
505
506 // Expand it. We need to offset any errors by the position of the string.
507 completion_list_t switch_values_expanded;
508 parse_error_list_t errors;
509 auto expand_ret =
510 expand_string(switch_value, &switch_values_expanded, expand_flags_t{}, ctx, &errors);
511 parse_error_offset_source_start(&errors, statement.argument.range.start);
512
513 switch (expand_ret.result) {
514 case expand_result_t::error:
515 return report_errors(expand_ret.status, errors);
516
517 case expand_result_t::cancel:
518 return end_execution_reason_t::cancelled;
519
520 case expand_result_t::wildcard_no_match:
521 return report_error(STATUS_UNMATCHED_WILDCARD, statement.argument, WILDCARD_ERR_MSG,
522 get_source(statement.argument).c_str());
523
524 case expand_result_t::ok:
525 if (switch_values_expanded.size() > 1) {
526 return report_error(STATUS_INVALID_ARGS, statement.argument,
527 _(L"switch: Expected at most one argument, got %lu\n"),
528 switch_values_expanded.size());
529 }
530 break;
531 }
532
533 // If we expanded to nothing, match the empty string.
534 assert(switch_values_expanded.size() <= 1 && "Should have at most one expansion");
535 wcstring switch_value_expanded;
536 if (!switch_values_expanded.empty()) {
537 switch_value_expanded = std::move(switch_values_expanded.front().completion);
538 }
539
540 end_execution_reason_t result = end_execution_reason_t::ok;
541 if (trace_enabled(*parser)) trace_argv(*parser, L"switch", {switch_value_expanded});
542 block_t *sb = parser->push_block(block_t::switch_block());
543
544 // Expand case statements.
545 const ast::case_item_t *matching_case_item = nullptr;
546 for (const ast::case_item_t &case_item : statement.cases) {
547 if (auto ret = check_end_execution()) {
548 result = *ret;
549 break;
550 }
551
552 // Expand arguments. A case item list may have a wildcard that fails to expand to
553 // anything. We also report case errors, but don't stop execution; i.e. a case item that
554 // contains an unexpandable process will report and then fail to match.
555 ast_args_list_t arg_nodes = get_argument_nodes(case_item.arguments);
556 wcstring_list_t case_args;
557 end_execution_reason_t case_result =
558 this->expand_arguments_from_nodes(arg_nodes, &case_args, failglob);
559 if (case_result == end_execution_reason_t::ok) {
560 for (const wcstring &arg : case_args) {
561 // Unescape wildcards so they can be expanded again.
562 wcstring unescaped_arg = parse_util_unescape_wildcards(arg);
563 bool match = wildcard_match(switch_value_expanded, unescaped_arg);
564
565 // If this matched, we're done.
566 if (match) {
567 matching_case_item = &case_item;
568 break;
569 }
570 }
571 }
572 if (matching_case_item) break;
573 }
574
575 if (matching_case_item) {
576 // Success, evaluate the job list.
577 assert(result == end_execution_reason_t::ok && "Expected success");
578 result = this->run_job_list(matching_case_item->body, sb);
579 }
580
581 parser->pop_block(sb);
582 trace_if_enabled(*parser, L"end switch");
583 return result;
584 }
585
run_while_statement(const ast::while_header_t & header,const ast::job_list_t & contents,const block_t * associated_block)586 end_execution_reason_t parse_execution_context_t::run_while_statement(
587 const ast::while_header_t &header, const ast::job_list_t &contents,
588 const block_t *associated_block) {
589 end_execution_reason_t ret = end_execution_reason_t::ok;
590
591 // "The exit status of the while loop shall be the exit status of the last compound-list-2
592 // executed, or zero if none was executed."
593 // Here are more detailed requirements:
594 // - If we execute the loop body zero times, or the loop body is empty, the status is success.
595 // - An empty loop body is treated as true, both in the loop condition and after loop exit.
596 // - The exit status of the last command is visible in the loop condition. (i.e. do not set the
597 // exit status to true BEFORE executing the loop condition).
598 // We achieve this by restoring the status if the loop condition fails, plus a special
599 // affordance for the first condition.
600 bool first_cond_check = true;
601
602 trace_if_enabled(*parser, L"while");
603
604 // Run while the condition is true.
605 for (;;) {
606 // Save off the exit status if it came from the loop body. We'll restore it if the condition
607 // is false.
608 auto cond_saved_status =
609 first_cond_check ? statuses_t::just(EXIT_SUCCESS) : parser->get_last_statuses();
610 first_cond_check = false;
611
612 // Check the condition.
613 end_execution_reason_t cond_ret =
614 this->run_job_conjunction(header.condition, associated_block);
615 if (cond_ret == end_execution_reason_t::ok) {
616 cond_ret = run_job_list(header.andor_tail, associated_block);
617 }
618
619 // If the loop condition failed to execute, then exit the loop without modifying the exit
620 // status. If the loop condition executed with a failure status, restore the status and then
621 // exit the loop.
622 if (cond_ret != end_execution_reason_t::ok) {
623 break;
624 } else if (parser->get_last_status() != EXIT_SUCCESS) {
625 parser->set_last_statuses(cond_saved_status);
626 break;
627 }
628
629 // Check cancellation.
630 if (auto reason = check_end_execution()) {
631 ret = *reason;
632 break;
633 }
634
635 // Push a while block and then check its cancellation reason.
636 auto &ld = parser->libdata();
637 ld.loop_status = loop_status_t::normals;
638
639 block_t *wb = parser->push_block(block_t::while_block());
640 this->run_job_list(contents, wb);
641 auto cancel_reason = this->check_end_execution();
642 parser->pop_block(wb);
643
644 if (cancel_reason == end_execution_reason_t::control_flow) {
645 // Handle break or continue.
646 bool do_break = (ld.loop_status == loop_status_t::breaks);
647 ld.loop_status = loop_status_t::normals;
648 if (do_break) {
649 break;
650 } else {
651 continue;
652 }
653 }
654
655 // no_exec means that fish was invoked with -n or --no-execute. If set, we allow the loop to
656 // not-execute once so its contents can be checked, and then break.
657 if (no_exec()) {
658 break;
659 }
660 }
661 trace_if_enabled(*parser, L"end while");
662 return ret;
663 }
664
665 // Reports an error. Always returns end_execution_reason_t::error.
report_error(int status,const ast::node_t & node,const wchar_t * fmt,...) const666 end_execution_reason_t parse_execution_context_t::report_error(int status, const ast::node_t &node,
667 const wchar_t *fmt, ...) const {
668 auto r = node.source_range();
669
670 // Create an error.
671 parse_error_list_t error_list = parse_error_list_t(1);
672 parse_error_t *error = &error_list.at(0);
673 error->source_start = r.start;
674 error->source_length = r.length;
675 error->code = parse_error_syntax; // hackish
676
677 va_list va;
678 va_start(va, fmt);
679 error->text = vformat_string(fmt, va);
680 va_end(va);
681
682 return this->report_errors(status, error_list);
683 }
684
report_errors(int status,const parse_error_list_t & error_list) const685 end_execution_reason_t parse_execution_context_t::report_errors(
686 int status, const parse_error_list_t &error_list) const {
687 if (!ctx.check_cancel()) {
688 if (error_list.empty()) {
689 FLOG(error, L"Error reported but no error text found.");
690 }
691
692 // Get a backtrace.
693 wcstring backtrace_and_desc;
694 parser->get_backtrace(pstree->src, error_list, backtrace_and_desc);
695
696 // Print it.
697 if (!should_suppress_stderr_for_tests()) {
698 std::fwprintf(stderr, L"%ls", backtrace_and_desc.c_str());
699 }
700
701 // Mark status.
702 parser->set_last_statuses(statuses_t::just(status));
703 }
704 return end_execution_reason_t::error;
705 }
706
707 // static
get_argument_nodes(const ast::argument_list_t & args)708 parse_execution_context_t::ast_args_list_t parse_execution_context_t::get_argument_nodes(
709 const ast::argument_list_t &args) {
710 ast_args_list_t result;
711 for (const ast::argument_t &arg : args) result.push_back(&arg);
712 return result;
713 }
714
715 // static
get_argument_nodes(const ast::argument_or_redirection_list_t & args)716 parse_execution_context_t::ast_args_list_t parse_execution_context_t::get_argument_nodes(
717 const ast::argument_or_redirection_list_t &args) {
718 ast_args_list_t result;
719 for (const ast::argument_or_redirection_t &v : args) {
720 if (v.is_argument()) result.push_back(&v.argument());
721 }
722 return result;
723 }
724
725 /// Handle the case of command not found.
handle_command_not_found(const wcstring & cmd_str,const ast::decorated_statement_t & statement,int err_code)726 end_execution_reason_t parse_execution_context_t::handle_command_not_found(
727 const wcstring &cmd_str, const ast::decorated_statement_t &statement, int err_code) {
728 // We couldn't find the specified command. This is a non-fatal error. We want to set the exit
729 // status to 127, which is the standard number used by other shells like bash and zsh.
730
731 const wchar_t *const cmd = cmd_str.c_str();
732 if (err_code != ENOENT) {
733 return this->report_error(STATUS_NOT_EXECUTABLE, statement,
734 _(L"The file '%ls' is not executable by this user"), cmd);
735 }
736
737 // Handle unrecognized commands with standard command not found handler that can make better
738 // error messages.
739 wcstring_list_t event_args;
740 {
741 ast_args_list_t args = get_argument_nodes(statement.args_or_redirs);
742 end_execution_reason_t arg_result =
743 this->expand_arguments_from_nodes(args, &event_args, failglob);
744
745 if (arg_result != end_execution_reason_t::ok) {
746 return arg_result;
747 }
748
749 event_args.insert(event_args.begin(), cmd_str);
750 }
751
752 wcstring buffer;
753 wcstring error;
754
755 // Redirect to stderr
756 auto io = io_chain_t{};
757 io.append_from_specs({redirection_spec_t{STDOUT_FILENO, redirection_mode_t::fd, L"2"}}, L"");
758
759 if (function_exists(L"fish_command_not_found", *parser)) {
760 buffer = L"fish_command_not_found";
761 for (const wcstring &arg : event_args) {
762 buffer.push_back(L' ');
763 buffer.append(escape_string(arg, ESCAPE_ALL));
764 }
765 auto prev_statuses = parser->get_last_statuses();
766
767 event_t event(event_type_t::generic);
768 event.desc.str_param1 = L"fish_command_not_found";
769 block_t *b = parser->push_block(block_t::event_block(event));
770 parser->eval(buffer, io);
771 parser->pop_block(b);
772 parser->set_last_statuses(std::move(prev_statuses));
773 } else {
774 // If we have no handler, just print it as a normal error.
775 error = _(L"Unknown command:");
776 if (!event_args.empty()) {
777 error.push_back(L' ');
778 error.append(escape_string(event_args[0], ESCAPE_ALL));
779 }
780 }
781
782 if (!cmd_str.empty() && cmd_str.at(0) == L'{') {
783 error.append(ERROR_NO_BRACE_GROUPING);
784 }
785
786 // Here we want to report an error (so it shows a backtrace).
787 // If the handler printed text, that's already shown, so error will be empty.
788 return this->report_error(STATUS_CMD_UNKNOWN, statement, error.c_str());
789 }
790
expand_command(const ast::decorated_statement_t & statement,wcstring * out_cmd,wcstring_list_t * out_args) const791 end_execution_reason_t parse_execution_context_t::expand_command(
792 const ast::decorated_statement_t &statement, wcstring *out_cmd,
793 wcstring_list_t *out_args) const {
794 // Here we're expanding a command, for example $HOME/bin/stuff or $randomthing. The first
795 // completion becomes the command itself, everything after becomes arguments. Command
796 // substitutions are not supported.
797 parse_error_list_t errors;
798
799 // Get the unexpanded command string. We expect to always get it here.
800 wcstring unexp_cmd = get_source(statement.command);
801 size_t pos_of_command_token = statement.command.range.start;
802
803 // Expand the string to produce completions, and report errors.
804 expand_result_t expand_err =
805 expand_to_command_and_args(unexp_cmd, ctx, out_cmd, out_args, &errors);
806 if (expand_err == expand_result_t::error) {
807 // Issue #5812 - the expansions were done on the command token,
808 // excluding prefixes such as " " or "if ".
809 // This means that the error positions are relative to the beginning
810 // of the token; we need to make them relative to the original source.
811 parse_error_offset_source_start(&errors, pos_of_command_token);
812 return report_errors(STATUS_ILLEGAL_CMD, errors);
813 } else if (expand_err == expand_result_t::wildcard_no_match) {
814 return report_error(STATUS_UNMATCHED_WILDCARD, statement, WILDCARD_ERR_MSG,
815 get_source(statement).c_str());
816 }
817 assert(expand_err == expand_result_t::ok);
818
819 // Complain if the resulting expansion was empty, or expanded to an empty string.
820 // For no-exec it's okay, as we can't really perform the expansion.
821 if (out_cmd->empty() && !no_exec()) {
822 return this->report_error(STATUS_ILLEGAL_CMD, statement,
823 _(L"The expanded command was empty."));
824 }
825 return end_execution_reason_t::ok;
826 }
827
828 /// Creates a 'normal' (non-block) process.
populate_plain_process(job_t * job,process_t * proc,const ast::decorated_statement_t & statement)829 end_execution_reason_t parse_execution_context_t::populate_plain_process(
830 job_t *job, process_t *proc, const ast::decorated_statement_t &statement) {
831 assert(job != nullptr);
832 assert(proc != nullptr);
833
834 // We may decide that a command should be an implicit cd.
835 bool use_implicit_cd = false;
836
837 // Get the command and any arguments due to expanding the command.
838 wcstring cmd;
839 wcstring_list_t args_from_cmd_expansion;
840 auto ret = expand_command(statement, &cmd, &args_from_cmd_expansion);
841 if (ret != end_execution_reason_t::ok) {
842 return ret;
843 }
844 // For no-exec, having an empty command is okay. We can't do anything more with it tho.
845 if (no_exec()) return end_execution_reason_t::ok;
846 assert(!cmd.empty() && "expand_command should not produce an empty command");
847
848 // Determine the process type.
849 enum process_type_t process_type = process_type_for_command(statement, cmd);
850
851 wcstring path_to_external_command;
852 if (process_type == process_type_t::external || process_type == process_type_t::exec) {
853 // Determine the actual command. This may be an implicit cd.
854 bool has_command = path_get_path(cmd, &path_to_external_command, parser->vars());
855
856 // If there was no command, then we care about the value of errno after checking for it, to
857 // distinguish between e.g. no file vs permissions problem.
858 const int no_cmd_err_code = errno;
859
860 // If the specified command does not exist, and is undecorated, try using an implicit cd.
861 if (!has_command && statement.decoration() == statement_decoration_t::none) {
862 // Implicit cd requires an empty argument and redirection list.
863 if (statement.args_or_redirs.empty()) {
864 // Ok, no arguments or redirections; check to see if the command is a directory.
865 use_implicit_cd =
866 path_as_implicit_cd(cmd, parser->vars().get_pwd_slash(), parser->vars())
867 .has_value();
868 }
869 }
870
871 if (!has_command && !use_implicit_cd) {
872 // No command. If we're --no-execute return okay - it might be a function.
873 if (no_exec()) return end_execution_reason_t::ok;
874 return this->handle_command_not_found(cmd, statement, no_cmd_err_code);
875 }
876 }
877
878 // Produce the full argument list and the set of IO redirections.
879 wcstring_list_t cmd_args;
880 redirection_spec_list_t redirections;
881 if (use_implicit_cd) {
882 // Implicit cd is simple.
883 cmd_args = {L"cd", cmd};
884 path_to_external_command.clear();
885
886 // If we have defined a wrapper around cd, use it, otherwise use the cd builtin.
887 process_type =
888 function_exists(L"cd", *parser) ? process_type_t::function : process_type_t::builtin;
889 } else {
890 // Not implicit cd.
891 const globspec_t glob_behavior = (cmd == L"set" || cmd == L"count") ? nullglob : failglob;
892 // Form the list of arguments. The command is the first argument, followed by any arguments
893 // from expanding the command, followed by the argument nodes themselves. E.g. if the
894 // command is '$gco foo' and $gco is git checkout.
895 cmd_args.push_back(cmd);
896 cmd_args.insert(cmd_args.end(), args_from_cmd_expansion.begin(),
897 args_from_cmd_expansion.end());
898
899 ast_args_list_t arg_nodes = get_argument_nodes(statement.args_or_redirs);
900 end_execution_reason_t arg_result =
901 this->expand_arguments_from_nodes(arg_nodes, &cmd_args, glob_behavior);
902 if (arg_result != end_execution_reason_t::ok) {
903 return arg_result;
904 }
905
906 // The set of IO redirections that we construct for the process.
907 auto reason = this->determine_redirections(statement.args_or_redirs, &redirections);
908 if (reason != end_execution_reason_t::ok) {
909 return reason;
910 }
911
912 // Determine the process type.
913 process_type = process_type_for_command(statement, cmd);
914 }
915
916 // Populate the process.
917 proc->type = process_type;
918 proc->set_argv(cmd_args);
919 proc->set_redirection_specs(std::move(redirections));
920 proc->actual_cmd = std::move(path_to_external_command);
921 return end_execution_reason_t::ok;
922 }
923
924 // Determine the list of arguments, expanding stuff. Reports any errors caused by expansion. If we
925 // have a wildcard that could not be expanded, report the error and continue.
expand_arguments_from_nodes(const ast_args_list_t & argument_nodes,wcstring_list_t * out_arguments,globspec_t glob_behavior)926 end_execution_reason_t parse_execution_context_t::expand_arguments_from_nodes(
927 const ast_args_list_t &argument_nodes, wcstring_list_t *out_arguments,
928 globspec_t glob_behavior) {
929 // Get all argument nodes underneath the statement. We guess we'll have that many arguments (but
930 // may have more or fewer, if there are wildcards involved).
931 out_arguments->reserve(out_arguments->size() + argument_nodes.size());
932 completion_list_t arg_expanded;
933 for (const ast::argument_t *arg_node : argument_nodes) {
934 // Expect all arguments to have source.
935 assert(arg_node->has_source() && "Argument should have source");
936
937 // Expand this string.
938 parse_error_list_t errors;
939 arg_expanded.clear();
940 auto expand_ret =
941 expand_string(get_source(*arg_node), &arg_expanded, expand_flags_t{}, ctx, &errors);
942 parse_error_offset_source_start(&errors, arg_node->range.start);
943 switch (expand_ret.result) {
944 case expand_result_t::error: {
945 return this->report_errors(expand_ret.status, errors);
946 }
947
948 case expand_result_t::cancel: {
949 return end_execution_reason_t::cancelled;
950 }
951 case expand_result_t::wildcard_no_match: {
952 if (glob_behavior == failglob) {
953 // For no_exec, ignore the error - this might work at runtime.
954 if (no_exec()) return end_execution_reason_t::ok;
955 // Report the unmatched wildcard error and stop processing.
956 return report_error(STATUS_UNMATCHED_WILDCARD, *arg_node, WILDCARD_ERR_MSG,
957 get_source(*arg_node).c_str());
958 }
959 break;
960 }
961 case expand_result_t::ok: {
962 break;
963 }
964 default: {
965 DIE("unexpected expand_string() return value");
966 }
967 }
968
969 // Now copy over any expanded arguments. Use std::move() to avoid extra allocations; this
970 // is called very frequently.
971 out_arguments->reserve(out_arguments->size() + arg_expanded.size());
972 for (completion_t &new_arg : arg_expanded) {
973 out_arguments->push_back(std::move(new_arg.completion));
974 }
975 }
976
977 // We may have received a cancellation during this expansion.
978 if (auto ret = check_end_execution()) {
979 return *ret;
980 }
981
982 return end_execution_reason_t::ok;
983 }
984
determine_redirections(const ast::argument_or_redirection_list_t & list,redirection_spec_list_t * out_redirections)985 end_execution_reason_t parse_execution_context_t::determine_redirections(
986 const ast::argument_or_redirection_list_t &list, redirection_spec_list_t *out_redirections) {
987 // Get all redirection nodes underneath the statement.
988 for (const ast::argument_or_redirection_t &arg_or_redir : list) {
989 if (!arg_or_redir.is_redirection()) continue;
990 const ast::redirection_t &redir_node = arg_or_redir.redirection();
991
992 maybe_t<pipe_or_redir_t> oper = pipe_or_redir_t::from_string(get_source(redir_node.oper));
993 if (!oper || !oper->is_valid()) {
994 // TODO: figure out if this can ever happen. If so, improve this error message.
995 return report_error(STATUS_INVALID_ARGS, redir_node, _(L"Invalid redirection: %ls"),
996 get_source(redir_node).c_str());
997 }
998
999 // PCA: I can't justify this skip_variables flag. It was like this when I got here.
1000 wcstring target = get_source(redir_node.target);
1001 bool target_expanded =
1002 expand_one(target, no_exec() ? expand_flag::skip_variables : expand_flags_t{}, ctx);
1003 if (!target_expanded || target.empty()) {
1004 // TODO: Improve this error message.
1005 return report_error(STATUS_INVALID_ARGS, redir_node,
1006 _(L"Invalid redirection target: %ls"), target.c_str());
1007 }
1008
1009 // Make a redirection spec from the redirect token.
1010 assert(oper && oper->is_valid() && "expected to have a valid redirection");
1011 redirection_spec_t spec{oper->fd, oper->mode, std::move(target)};
1012
1013 // Validate this spec.
1014 if (spec.mode == redirection_mode_t::fd && !spec.is_close() && !spec.get_target_as_fd()) {
1015 const wchar_t *fmt =
1016 _(L"Requested redirection to '%ls', which is not a valid file descriptor");
1017 return report_error(STATUS_INVALID_ARGS, redir_node, fmt, spec.target.c_str());
1018 }
1019 out_redirections->push_back(std::move(spec));
1020
1021 if (oper->stderr_merge) {
1022 // This was a redirect like &> which also modifies stderr.
1023 // Also redirect stderr to stdout.
1024 out_redirections->push_back(get_stderr_merge());
1025 }
1026 }
1027 return end_execution_reason_t::ok;
1028 }
1029
populate_not_process(job_t * job,process_t * proc,const ast::not_statement_t & not_statement)1030 end_execution_reason_t parse_execution_context_t::populate_not_process(
1031 job_t *job, process_t *proc, const ast::not_statement_t ¬_statement) {
1032 auto &flags = job->mut_flags();
1033 flags.negate = !flags.negate;
1034 return this->populate_job_process(job, proc, not_statement.contents, not_statement.variables);
1035 }
1036
1037 template <typename Type>
populate_block_process(job_t * job,process_t * proc,const ast::statement_t & statement,const Type & specific_statement)1038 end_execution_reason_t parse_execution_context_t::populate_block_process(
1039 job_t *job, process_t *proc, const ast::statement_t &statement,
1040 const Type &specific_statement) {
1041 using namespace ast;
1042 // We handle block statements by creating process_type_t::block_node, that will bounce back to
1043 // us when it's time to execute them.
1044 UNUSED(job);
1045 static_assert(Type::AstType == type_t::block_statement ||
1046 Type::AstType == type_t::if_statement ||
1047 Type::AstType == type_t::switch_statement,
1048 "Invalid block process");
1049
1050 // Get the argument or redirections list.
1051 // TODO: args_or_redirs should be available without resolving the statement type.
1052 const argument_or_redirection_list_t *args_or_redirs = nullptr;
1053
1054 // Upcast to permit dropping the 'template' keyword.
1055 const node_t &ss = specific_statement;
1056 switch (Type::AstType) {
1057 case type_t::block_statement:
1058 args_or_redirs = &ss.as<block_statement_t>()->args_or_redirs;
1059 break;
1060 case type_t::if_statement:
1061 args_or_redirs = &ss.as<if_statement_t>()->args_or_redirs;
1062 break;
1063 case type_t::switch_statement:
1064 args_or_redirs = &ss.as<switch_statement_t>()->args_or_redirs;
1065 break;
1066 default:
1067 DIE("Unexpected block node type");
1068 }
1069 assert(args_or_redirs && "Should have args_or_redirs");
1070
1071 redirection_spec_list_t redirections;
1072 auto reason = this->determine_redirections(*args_or_redirs, &redirections);
1073 if (reason == end_execution_reason_t::ok) {
1074 proc->type = process_type_t::block_node;
1075 proc->block_node_source = pstree;
1076 proc->internal_block_node = &statement;
1077 proc->set_redirection_specs(std::move(redirections));
1078 }
1079 return reason;
1080 }
1081
apply_variable_assignments(process_t * proc,const ast::variable_assignment_list_t & variable_assignment_list,const block_t ** block)1082 end_execution_reason_t parse_execution_context_t::apply_variable_assignments(
1083 process_t *proc, const ast::variable_assignment_list_t &variable_assignment_list,
1084 const block_t **block) {
1085 if (variable_assignment_list.empty()) return end_execution_reason_t::ok;
1086 *block = parser->push_block(block_t::variable_assignment_block());
1087 for (const ast::variable_assignment_t &variable_assignment : variable_assignment_list) {
1088 const wcstring &source = get_source(variable_assignment);
1089 auto equals_pos = variable_assignment_equals_pos(source);
1090 assert(equals_pos);
1091 const wcstring variable_name = source.substr(0, *equals_pos);
1092 const wcstring expression = source.substr(*equals_pos + 1);
1093 completion_list_t expression_expanded;
1094 parse_error_list_t errors;
1095 // TODO this is mostly copied from expand_arguments_from_nodes, maybe extract to function
1096 auto expand_ret =
1097 expand_string(expression, &expression_expanded, expand_flags_t{}, ctx, &errors);
1098 parse_error_offset_source_start(&errors, variable_assignment.range.start + *equals_pos + 1);
1099 switch (expand_ret.result) {
1100 case expand_result_t::error:
1101 return this->report_errors(expand_ret.status, errors);
1102
1103 case expand_result_t::cancel:
1104 return end_execution_reason_t::cancelled;
1105
1106 case expand_result_t::wildcard_no_match: // nullglob (equivalent to set)
1107 case expand_result_t::ok:
1108 break;
1109
1110 default: {
1111 DIE("unexpected expand_string() return value");
1112 }
1113 }
1114 wcstring_list_t vals;
1115 for (auto &completion : expression_expanded) {
1116 vals.emplace_back(std::move(completion.completion));
1117 }
1118 if (proc) proc->variable_assignments.push_back({variable_name, vals});
1119 parser->set_var_and_fire(variable_name, ENV_LOCAL | ENV_EXPORT, std::move(vals));
1120 }
1121 return end_execution_reason_t::ok;
1122 }
1123
populate_job_process(job_t * job,process_t * proc,const ast::statement_t & statement,const ast::variable_assignment_list_t & variable_assignments)1124 end_execution_reason_t parse_execution_context_t::populate_job_process(
1125 job_t *job, process_t *proc, const ast::statement_t &statement,
1126 const ast::variable_assignment_list_t &variable_assignments) {
1127 using namespace ast;
1128 // Get the "specific statement" which is boolean / block / if / switch / decorated.
1129 const node_t &specific_statement = *statement.contents.contents;
1130
1131 const block_t *block = nullptr;
1132 end_execution_reason_t result =
1133 this->apply_variable_assignments(proc, variable_assignments, &block);
1134 cleanup_t scope([&]() {
1135 if (block) parser->pop_block(block);
1136 });
1137 if (result != end_execution_reason_t::ok) return result;
1138
1139 switch (specific_statement.type) {
1140 case type_t::not_statement: {
1141 result =
1142 this->populate_not_process(job, proc, *specific_statement.as<not_statement_t>());
1143 break;
1144 }
1145 case type_t::block_statement:
1146 result = this->populate_block_process(job, proc, statement,
1147 *specific_statement.as<block_statement_t>());
1148 break;
1149 case type_t::if_statement:
1150 result = this->populate_block_process(job, proc, statement,
1151 *specific_statement.as<if_statement_t>());
1152 break;
1153 case type_t::switch_statement:
1154 result = this->populate_block_process(job, proc, statement,
1155 *specific_statement.as<switch_statement_t>());
1156 break;
1157 case type_t::decorated_statement: {
1158 result = this->populate_plain_process(job, proc,
1159 *specific_statement.as<decorated_statement_t>());
1160 break;
1161 }
1162 default: {
1163 FLOGF(error, L"'%ls' not handled by new parser yet.",
1164 specific_statement.describe().c_str());
1165 PARSER_DIE();
1166 break;
1167 }
1168 }
1169
1170 return result;
1171 }
1172
populate_job_from_job_node(job_t * j,const ast::job_t & job_node,const block_t * associated_block)1173 end_execution_reason_t parse_execution_context_t::populate_job_from_job_node(
1174 job_t *j, const ast::job_t &job_node, const block_t *associated_block) {
1175 UNUSED(associated_block);
1176
1177 // We are going to construct process_t structures for every statement in the job.
1178 // Create processes. Each one may fail.
1179 process_list_t processes;
1180 processes.emplace_back(new process_t());
1181 end_execution_reason_t result = this->populate_job_process(
1182 j, processes.back().get(), job_node.statement, job_node.variables);
1183
1184 // Construct process_ts for job continuations (pipelines).
1185 for (const ast::job_continuation_t &jc : job_node.continuation) {
1186 if (result != end_execution_reason_t::ok) {
1187 break;
1188 }
1189 // Handle the pipe, whose fd may not be the obvious stdout.
1190 auto parsed_pipe = pipe_or_redir_t::from_string(get_source(jc.pipe));
1191 assert(parsed_pipe.has_value() && parsed_pipe->is_pipe && "Failed to parse valid pipe");
1192 if (!parsed_pipe->is_valid()) {
1193 result = report_error(STATUS_INVALID_ARGS, jc.pipe, ILLEGAL_FD_ERR_MSG,
1194 get_source(jc.pipe).c_str());
1195 break;
1196 }
1197 processes.back()->pipe_write_fd = parsed_pipe->fd;
1198 if (parsed_pipe->stderr_merge) {
1199 // This was a pipe like &| which redirects both stdout and stderr.
1200 // Also redirect stderr to stdout.
1201 auto specs = processes.back()->redirection_specs();
1202 specs.push_back(get_stderr_merge());
1203 processes.back()->set_redirection_specs(std::move(specs));
1204 }
1205
1206 // Store the new process (and maybe with an error).
1207 processes.emplace_back(new process_t());
1208 result = this->populate_job_process(j, processes.back().get(), jc.statement, jc.variables);
1209 }
1210
1211 // Inform our processes of who is first and last
1212 processes.front()->is_first_in_job = true;
1213 processes.back()->is_last_in_job = true;
1214
1215 // Return what happened.
1216 if (result == end_execution_reason_t::ok) {
1217 // Link up the processes.
1218 assert(!processes.empty()); //!OCLINT(multiple unary operator)
1219 j->processes = std::move(processes);
1220 }
1221 return result;
1222 }
1223
remove_job(parser_t & parser,job_t * job)1224 static bool remove_job(parser_t &parser, job_t *job) {
1225 for (auto j = parser.jobs().begin(); j != parser.jobs().end(); ++j) {
1226 if (j->get() == job) {
1227 parser.jobs().erase(j);
1228 return true;
1229 }
1230 }
1231 return false;
1232 }
1233
1234 /// Decide if a job node should be 'time'd.
1235 /// For historical reasons the 'not' and 'time' prefix are "inside out". That is, it's
1236 /// 'not time cmd'. Note that a time appearing anywhere in the pipeline affects the whole job.
1237 /// `sleep 1 | not time true` will time the whole job!
job_node_wants_timing(const ast::job_t & job_node)1238 static bool job_node_wants_timing(const ast::job_t &job_node) {
1239 // Does our job have the job-level time prefix?
1240 if (job_node.time) return true;
1241
1242 // Helper to return true if a node is 'not time ...' or 'not not time...' or...
1243 auto is_timed_not_statement = [](const ast::statement_t &stat) {
1244 const auto *ns = stat.contents->try_as<ast::not_statement_t>();
1245 while (ns) {
1246 if (ns->time) return true;
1247 ns = ns->contents.try_as<ast::not_statement_t>();
1248 }
1249 return false;
1250 };
1251
1252 // Do we have a 'not time ...' anywhere in our pipeline?
1253 if (is_timed_not_statement(job_node.statement)) return true;
1254 for (const ast::job_continuation_t &jc : job_node.continuation) {
1255 if (is_timed_not_statement(jc.statement)) return true;
1256 }
1257 return false;
1258 }
1259
run_1_job(const ast::job_t & job_node,const block_t * associated_block)1260 end_execution_reason_t parse_execution_context_t::run_1_job(const ast::job_t &job_node,
1261 const block_t *associated_block) {
1262 if (auto ret = check_end_execution()) {
1263 return *ret;
1264 }
1265
1266 // We definitely do not want to execute anything if we're told we're --no-execute!
1267 if (no_exec()) return end_execution_reason_t::ok;
1268
1269 // Get terminal modes.
1270 struct termios tmodes = {};
1271 if (parser->is_interactive() && tcgetattr(STDIN_FILENO, &tmodes)) {
1272 // Need real error handling here.
1273 wperror(L"tcgetattr");
1274 parser->set_last_statuses(statuses_t::just(STATUS_CMD_ERROR));
1275 return end_execution_reason_t::error;
1276 }
1277
1278 // Increment the eval_level for the duration of this command.
1279 scoped_push<int> saved_eval_level(&parser->eval_level, parser->eval_level + 1);
1280
1281 // Save the node index.
1282 scoped_push<const ast::job_t *> saved_node(&executing_job_node, &job_node);
1283
1284 // Profiling support.
1285 profile_item_t *profile_item = this->parser->create_profile_item();
1286 const auto start_time = profile_item ? profile_item_t::now() : 0;
1287
1288 // When we encounter a block construct (e.g. while loop) in the general case, we create a "block
1289 // process" containing its node. This allows us to handle block-level redirections.
1290 // However, if there are no redirections, then we can just jump into the block directly, which
1291 // is significantly faster.
1292 if (job_is_simple_block(job_node)) {
1293 bool do_time = job_node.time.has_value();
1294 // If no-exec has been given, there is nothing to time.
1295 cleanup_t timer = push_timer(do_time && !no_exec());
1296 const block_t *block = nullptr;
1297 end_execution_reason_t result =
1298 this->apply_variable_assignments(nullptr, job_node.variables, &block);
1299 cleanup_t scope([&]() {
1300 if (block) parser->pop_block(block);
1301 });
1302
1303 const ast::node_t *specific_statement = job_node.statement.contents.get();
1304 assert(specific_statement_type_is_redirectable_block(*specific_statement));
1305 if (result == end_execution_reason_t::ok) {
1306 switch (specific_statement->type) {
1307 case ast::type_t::block_statement: {
1308 result = this->run_block_statement(
1309 *specific_statement->as<ast::block_statement_t>(), associated_block);
1310 break;
1311 }
1312 case ast::type_t::if_statement: {
1313 result = this->run_if_statement(*specific_statement->as<ast::if_statement_t>(),
1314 associated_block);
1315 break;
1316 }
1317 case ast::type_t::switch_statement: {
1318 result = this->run_switch_statement(
1319 *specific_statement->as<ast::switch_statement_t>());
1320 break;
1321 }
1322 default: {
1323 // Other types should be impossible due to the
1324 // specific_statement_type_is_redirectable_block check.
1325 PARSER_DIE();
1326 break;
1327 }
1328 }
1329 }
1330
1331 if (profile_item != nullptr) {
1332 profile_item->duration = profile_item_t::now() - start_time;
1333 profile_item->level = parser->eval_level;
1334 profile_item->cmd =
1335 profiling_cmd_name_for_redirectable_block(*specific_statement, *this->pstree);
1336 profile_item->skipped = false;
1337 }
1338
1339 return result;
1340 }
1341
1342 const auto &ld = parser->libdata();
1343
1344 auto job_control_mode = get_job_control_mode();
1345 bool wants_job_control =
1346 (job_control_mode == job_control_t::all) ||
1347 ((job_control_mode == job_control_t::interactive) && parser->is_interactive()) ||
1348 (ctx.job_group && ctx.job_group->wants_job_control());
1349
1350 job_t::properties_t props{};
1351 props.initial_background = job_node.bg.has_value();
1352 props.skip_notification =
1353 ld.is_subshell || ld.is_block || ld.is_event || !parser->is_interactive();
1354 props.from_event_handler = ld.is_event;
1355 props.job_control = wants_job_control;
1356 props.wants_timing = job_node_wants_timing(job_node);
1357
1358 // It's an error to have 'time' in a background job.
1359 if (props.wants_timing && props.initial_background) {
1360 return this->report_error(STATUS_INVALID_ARGS, job_node, ERROR_TIME_BACKGROUND);
1361 }
1362
1363 shared_ptr<job_t> job = std::make_shared<job_t>(props, get_source(job_node));
1364
1365 // We are about to populate a job. One possible argument to the job is a command substitution
1366 // which may be interested in the job that's populating it, via '--on-job-exit caller'. Record
1367 // the job ID here.
1368 scoped_push<internal_job_id_t> caller_id(&parser->libdata().caller_id, job->internal_job_id);
1369
1370 // Populate the job. This may fail for reasons like command_not_found. If this fails, an error
1371 // will have been printed.
1372 end_execution_reason_t pop_result =
1373 this->populate_job_from_job_node(job.get(), job_node, associated_block);
1374 caller_id.restore();
1375
1376 // Clean up the job on failure or cancellation.
1377 if (pop_result == end_execution_reason_t::ok) {
1378 // Resolve the job's group and mark if this job is the first to get it.
1379 job->group = job_group_t::resolve_group_for_job(*job, cancel_group, ctx.job_group);
1380 assert(job->group && "Should not have a null group");
1381 job->mut_flags().is_group_root = (job->group != ctx.job_group);
1382
1383 // Success. Give the job to the parser - it will clean it up.
1384 parser->job_add(job);
1385
1386 // Check to see if this contained any external commands.
1387 bool job_contained_external_command = false;
1388 for (const auto &proc : job->processes) {
1389 if (proc->type == process_type_t::external) {
1390 job_contained_external_command = true;
1391 break;
1392 }
1393 }
1394
1395 // Actually execute the job.
1396 if (!exec_job(*parser, job, block_io)) {
1397 // No process in the job successfully launched.
1398 // Ensure statuses are set (#7540).
1399 if (auto statuses = job->get_statuses()) {
1400 parser->set_last_statuses(statuses.value());
1401 parser->libdata().status_count++;
1402 }
1403 remove_job(*this->parser, job.get());
1404 }
1405
1406 // Update universal variables on external conmmands.
1407 // TODO: justify this, why not on every command?
1408 if (job_contained_external_command) {
1409 parser->vars().universal_barrier();
1410 }
1411 }
1412
1413 if (profile_item != nullptr) {
1414 profile_item->duration = profile_item_t::now() - start_time;
1415 profile_item->level = parser->eval_level;
1416 profile_item->cmd = job ? job->command() : wcstring();
1417 profile_item->skipped = (pop_result != end_execution_reason_t::ok);
1418 }
1419
1420 job_reap(*parser, false); // clean up jobs
1421 return pop_result;
1422 }
1423
run_job_conjunction(const ast::job_conjunction_t & job_expr,const block_t * associated_block)1424 end_execution_reason_t parse_execution_context_t::run_job_conjunction(
1425 const ast::job_conjunction_t &job_expr, const block_t *associated_block) {
1426 if (auto reason = check_end_execution()) {
1427 return *reason;
1428 }
1429 end_execution_reason_t result = run_1_job(job_expr.job, associated_block);
1430
1431 for (const ast::job_conjunction_continuation_t &jc : job_expr.continuations) {
1432 if (result != end_execution_reason_t::ok) {
1433 return result;
1434 }
1435 if (auto reason = check_end_execution()) {
1436 return *reason;
1437 }
1438 // Check the conjunction type.
1439 bool skip = false;
1440 switch (jc.conjunction.type) {
1441 case parse_token_type_t::andand:
1442 // AND. Skip if the last job failed.
1443 skip = parser->get_last_status() != 0;
1444 break;
1445 case parse_token_type_t::oror:
1446 // OR. Skip if the last job succeeded.
1447 skip = parser->get_last_status() == 0;
1448 break;
1449 default:
1450 DIE("Unexpected job conjunction type");
1451 }
1452 if (!skip) {
1453 result = run_1_job(jc.job, associated_block);
1454 }
1455 }
1456 return result;
1457 }
1458
test_and_run_1_job_conjunction(const ast::job_conjunction_t & jc,const block_t * associated_block)1459 end_execution_reason_t parse_execution_context_t::test_and_run_1_job_conjunction(
1460 const ast::job_conjunction_t &jc, const block_t *associated_block) {
1461 // Test this job conjunction if it has an 'and' or 'or' decorator.
1462 // If it passes, then run it.
1463 if (auto reason = check_end_execution()) {
1464 return *reason;
1465 }
1466 // Maybe skip the job if it has a leading and/or.
1467 bool skip = false;
1468 if (jc.decorator.has_value()) {
1469 switch (jc.decorator->kw) {
1470 case parse_keyword_t::kw_and:
1471 // AND. Skip if the last job failed.
1472 skip = parser->get_last_status() != 0;
1473 break;
1474 case parse_keyword_t::kw_or:
1475 // OR. Skip if the last job succeeded.
1476 skip = parser->get_last_status() == 0;
1477 break;
1478 default:
1479 DIE("Unexpected keyword");
1480 }
1481 }
1482 // Skipping is treated as success.
1483 if (skip) {
1484 return end_execution_reason_t::ok;
1485 } else {
1486 return this->run_job_conjunction(jc, associated_block);
1487 }
1488 }
1489
run_job_list(const ast::job_list_t & job_list_node,const block_t * associated_block)1490 end_execution_reason_t parse_execution_context_t::run_job_list(const ast::job_list_t &job_list_node,
1491 const block_t *associated_block) {
1492 auto result = end_execution_reason_t::ok;
1493 for (const ast::job_conjunction_t &jc : job_list_node) {
1494 result = test_and_run_1_job_conjunction(jc, associated_block);
1495 }
1496 // Returns the result of the last job executed or skipped.
1497 return result;
1498 }
1499
run_job_list(const ast::andor_job_list_t & job_list_node,const block_t * associated_block)1500 end_execution_reason_t parse_execution_context_t::run_job_list(
1501 const ast::andor_job_list_t &job_list_node, const block_t *associated_block) {
1502 auto result = end_execution_reason_t::ok;
1503 for (const ast::andor_job_t &aoj : job_list_node) {
1504 result = test_and_run_1_job_conjunction(aoj.job, associated_block);
1505 }
1506 // Returns the result of the last job executed or skipped.
1507 return result;
1508 }
1509
eval_node(const ast::statement_t & statement,const block_t * associated_block)1510 end_execution_reason_t parse_execution_context_t::eval_node(const ast::statement_t &statement,
1511 const block_t *associated_block) {
1512 // Note we only expect block-style statements here. No not statements.
1513 enum end_execution_reason_t status = end_execution_reason_t::ok;
1514 const ast::node_t *contents = statement.contents.get();
1515 if (const auto *block = contents->try_as<ast::block_statement_t>()) {
1516 status = this->run_block_statement(*block, associated_block);
1517 } else if (const auto *ifstat = contents->try_as<ast::if_statement_t>()) {
1518 status = this->run_if_statement(*ifstat, associated_block);
1519 } else if (const auto *switchstat = contents->try_as<ast::switch_statement_t>()) {
1520 status = this->run_switch_statement(*switchstat);
1521 } else {
1522 FLOGF(error, L"Unexpected node %ls found in %s", statement.describe().c_str(),
1523 __FUNCTION__);
1524 abort();
1525 }
1526 return status;
1527 }
1528
eval_node(const ast::job_list_t & job_list,const block_t * associated_block)1529 end_execution_reason_t parse_execution_context_t::eval_node(const ast::job_list_t &job_list,
1530 const block_t *associated_block) {
1531 assert(associated_block && "Null block");
1532
1533 // Check for infinite recursion: a function which immediately calls itself..
1534 wcstring func_name;
1535 if (const auto *infinite_recursive_node =
1536 this->infinite_recursive_statement_in_job_list(job_list, &func_name)) {
1537 // We have an infinite recursion.
1538 return this->report_error(STATUS_CMD_ERROR, *infinite_recursive_node,
1539 INFINITE_FUNC_RECURSION_ERR_MSG, func_name.c_str());
1540 }
1541
1542 // Check for stack overflow. The TOP check ensures we only do this for function calls.
1543 if (associated_block->type() == block_type_t::top && parser->function_stack_is_overflowing()) {
1544 return this->report_error(STATUS_CMD_ERROR, job_list, CALL_STACK_LIMIT_EXCEEDED_ERR_MSG);
1545 }
1546 return this->run_job_list(job_list, associated_block);
1547 }
1548
line_offset_of_node(const ast::job_t * node)1549 int parse_execution_context_t::line_offset_of_node(const ast::job_t *node) {
1550 // If we're not executing anything, return -1.
1551 if (!node) {
1552 return -1;
1553 }
1554
1555 // If for some reason we're executing a node without source, return -1.
1556 auto range = node->try_source_range();
1557 if (!range) {
1558 return -1;
1559 }
1560
1561 return this->line_offset_of_character_at_offset(range->start);
1562 }
1563
line_offset_of_character_at_offset(size_t offset)1564 int parse_execution_context_t::line_offset_of_character_at_offset(size_t offset) {
1565 // Count the number of newlines, leveraging our cache.
1566 assert(offset <= pstree->src.size());
1567
1568 // Easy hack to handle 0.
1569 if (offset == 0) {
1570 return 0;
1571 }
1572
1573 // We want to return (one plus) the number of newlines at offsets less than the given offset.
1574 // cached_lineno_count is the number of newlines at indexes less than cached_lineno_offset.
1575 const wchar_t *str = pstree->src.c_str();
1576 if (offset > cached_lineno_offset) {
1577 size_t i;
1578 for (i = cached_lineno_offset; i < offset && str[i] != L'\0'; i++) {
1579 // Add one for every newline we find in the range [cached_lineno_offset, offset).
1580 if (str[i] == L'\n') {
1581 cached_lineno_count++;
1582 }
1583 }
1584 cached_lineno_offset =
1585 i; // note: i, not offset, in case offset is beyond the length of the string
1586 } else if (offset < cached_lineno_offset) {
1587 // Subtract one for every newline we find in the range [offset, cached_lineno_offset).
1588 for (size_t i = offset; i < cached_lineno_offset; i++) {
1589 if (str[i] == L'\n') {
1590 cached_lineno_count--;
1591 }
1592 }
1593 cached_lineno_offset = offset;
1594 }
1595 return cached_lineno_count;
1596 }
1597
get_current_line_number()1598 int parse_execution_context_t::get_current_line_number() {
1599 int line_number = -1;
1600 int line_offset = this->line_offset_of_node(this->executing_job_node);
1601 if (line_offset >= 0) {
1602 // The offset is 0 based; the number is 1 based.
1603 line_number = line_offset + 1;
1604 }
1605 return line_number;
1606 }
1607
get_current_source_offset() const1608 int parse_execution_context_t::get_current_source_offset() const {
1609 int result = -1;
1610 if (executing_job_node) {
1611 if (auto range = executing_job_node->try_source_range()) {
1612 result = static_cast<int>(range->start);
1613 }
1614 }
1615 return result;
1616 }
1617