Executor
Walks the AST and runs each node: simple commands, pipelines, logical operators, subshells, blocks, and background jobs.
Defines the executor functions for handling AST nodes.
- Author
zweng, pulgamecanica
Defines
-
MAX_PIPELINE
-
MAX_SAVED_FDS
-
CMD_HASH_BUCKETS
Default bucket count for the command-path hash table (prime, small).
Functions
-
void cmd_hash_init(struct s_shell *shell)
Allocate
shell->cmd_hashif not already present.
-
void cmd_hash_destroy(struct s_shell *shell)
Drop every entry and free the table itself. Safe to call repeatedly.
-
void cmd_hash_clear(struct s_shell *shell)
Drop every entry but keep the table allocated (for
hash -r).
-
t_cmd_hash_value *cmd_hash_get(struct s_shell *shell, const char *name)
Look up
namewithout bumping the hit counter.
-
int cmd_hash_set(struct s_shell *shell, const char *name, const char *path)
Insert or replace
name -> path(path is duplicated internally).Preserves the hit counter when
namealready exists, sohash -pdoesn’t reset history. Returns 1 on success, 0 on allocation failure (table left unchanged).
-
int cmd_hash_delete(struct s_shell *shell, const char *name)
Remove
name. Returns 1 if an entry was removed, 0 otherwise.
-
void cmd_hash_iter(struct s_shell *shell, void (*f)(const char*, t_cmd_hash_value*, void*), void *userdata)
Iterate every (name, value) pair in insertion-agnostic order.
-
int executor_execute(struct s_shell *shell, t_ast *ast)
Main dispatch function for executing AST nodes.
- Parameters:
shell – Pointer to the central shell state
ast – Pointer to the AST node to execute
- Returns:
Exit status code
-
int execute_simple_command(struct s_shell *shell, t_cmd *cmd)
Node-type executors.
- Parameters:
shell – Pointer to the central shell state
ast – Pointer to the AST node to execute
- Returns:
Exit status code
-
int setup_redirections(t_list *redirs, int saved_fds[3])
redirection setup
If saved_fds is not NULL, save stdin/stdout/stderr first (for restore).
- Parameters:
redirs – List of redirection nodes
saved_fds – Array to save original file descriptors
- Returns:
Exit status code
-
void restore_redirections(int saved_fds[3])
Restore redirections.
- Parameters:
saved_fds – Array of saved file descriptors
-
char *find_command(struct s_shell *shell, const char *name)
Command search (PATH)
- Parameters:
shell – Pointer to the central shell state
name – Name of the command to search for
- Returns:
Pointer to the found command, or NULL if not found
-
void exec_pipeline_external(struct s_shell *shell, t_cmd *cmd)
Pipeline helper (called from pipe_child, does not return)
- Parameters:
shell – Pointer to the central shell state
cmd – Pointer to the command node
-
int get_exit_status(int wstatus)
get exit status from wait status
Normal exit: WEXITSTATUS (0-255)
Killed by signal: 128 + signal number
- Parameters:
wstatus – Wait status code
- Returns:
Exit status code
-
void split_assignment(const char *assign, char **name, char **value)
Caller must free both *name and *value.
If no ‘=’ found, *name = dup of assign, *value = dup of “”.
-
void apply_assignments(struct s_shell *shell, t_list *assigns, int do_export)
Apply variable assignments to the shell (shared by the simple command and pipeline child paths).
- Parameters:
shell – The shell instance.
assigns – List of “NAME=value” assignment strings.
do_export – Whether to also export each variable.
-
int report_command_error(const char *name)
Print the diagnostic for an unrunnable command and return its exit status: 126 if the path exists but is not executable, 127 if it could not be found.
Print the diagnostic for an unrunnable command and return its exit status: 126 if the path exists but is not executable, 127 if it could not be found.
Distinguishes “exists but not executable” (126, permission denied) from “not found” (127). Only a name containing ‘/’ can be probed for existence on disk; a bare name that PATH search failed to resolve is reported as not found.
- Parameters:
name – The command name as typed.
name – The command name as typed.
- Returns:
126 or 127.
- Returns:
126 if the path exists but is not executable, 127 otherwise.
-
struct t_cmd_hash_value
- #include <executor.h>
Cached PATH lookup, indexed by command name in
shell->cmd_hash.pathis heap-allocated and owned by the value.hitstracks how many times the cache satisfied a lookup (read byhash).
Dispatch
Command execution functionality for 42sh.
- Author
wengzhang, pulgamecanica
Simple Commands
Command execution functionality for 42sh.
- Author
wengzhang, pulgamecanica
Functions
-
void apply_assignments(t_shell *shell, t_list *assigns, int do_export)
Apply assignments permanently to shell variables.
Used for a bare assignment, and in a forked child (a simple command or a pipeline stage) before execve.
- Parameters:
shell – The shell instance.
assigns – The list of assignments.
do_export – Whether to export the variables.
-
static int exec_assignment_only(t_shell *shell, t_cmd *cmd)
Handle empty command (just assignments and/or redirections).
Example: FOO=bar or FOO=bar > file
- Parameters:
shell – The shell instance.
cmd – The command structure.
- Returns:
0 on success, 1 on failure.
-
static int save_and_apply_assigns(t_shell *shell, t_list *assigns, char **old_names, char **old_vals)
Save old values, apply temporary assignments for builtin scope.
old_names/old_vals arrays store what to restore afterward.
- Parameters:
shell – The shell instance.
assigns – The list of assignments.
old_names – Array to store old variable names.
old_vals – Array to store old variable values.
- Returns:
Count of saved assignments.
-
static void restore_assigns(t_shell *shell, char **old_names, char **old_vals, int count)
Restore old variable values after builtin execution.
- Parameters:
shell – The shell instance.
old_names – Array of old variable names.
old_vals – Array of old variable values.
count – Number of assignments to restore.
-
static int exec_builtin(t_shell *shell, t_cmd *cmd, t_builtin_fn fn)
Execute a builtin with temporary assignments and redirections.
Assignments are scoped to this command only, then restored.
- Parameters:
shell – The shell instance.
cmd – The command structure.
fn – The builtin function to execute.
- Returns:
The exit status of the builtin.
-
static void exec_child(t_shell *shell, t_cmd *cmd)
Child process: place in own pgrp, apply assignments, exec.
setpgid(0, 0)race-free paired with parent-sidesetpgid(pid,pid);tcsetpgrphands the terminal off before the child could block on stdin (parent’s SIG_IGN for SIGTTOU is still inherited here).
-
static void prewarm_cmd_cache(t_shell *shell, t_cmd *cmd)
Resolve and cache the external command in the parent before forking, so the cache survives in the shell process.
Skipped when the command has prefix assignments - those may change
PATHfor this invocation only, so resolution must happen in the child after apply_assignments. The result is freed immediately; we’re only here to warmshell->cmd_hash.
Logical (&&, ||, ;)
Logical command execution functionality for 42sh.
- Author
wengzhang, pulgamecanica
Functions
Pipes
Pipeline command execution functionality for 42sh.
- Author
wengzhang, pulgamecanica
Functions
-
static int collect_pipeline(t_ast *ast, t_ast **cmds, int max)
Flatten nested PIPE nodes left-to-right into a flat array.
Example: (A | B) | C => [A, B, C]
-
static void close_pipes(int pipes[][2], int count)
-
static void pipe_child(t_shell *shell, t_ast *cmd_ast, int pipes[][2], int info[3])
Pipeline stage in the child: join the job pgrp, wire pipes, exec.
info = { stage_index, stage_count, group_pgid }. When
group_pgid == 0this stage becomes the pgrp leader; the parent mirrorssetpgidrace-free. Expansion of NODE_COMMAND stages is done in the parent before forking (see expand_pipeline_stages) so the child inherits the already-expanded argv and debug output stays in one process. The child also clearsinteractive(a forked stage is not the interactive shell) and applies one-shot assignments before redirections, mirroring exec_child.
-
static int open_pipes(int pipes[][2], int n)
-
static void prewarm_pipeline_cache(t_shell *shell, t_ast **cmds, int n)
Warm the command-path cache in the parent for each pipeline stage so cache hits survive the fork.
Mirrors prewarm_cmd_cache() in exec_command.c: skip builtins, absolute / relative paths, and stages with prefix assignments (the latter may shadow
PATHfor that stage only).
-
static void expand_pipeline_stages(t_shell *shell, t_ast **cmds, int n)
Expand every NODE_COMMAND stage in the parent before forking.
Runs the same expand_command pass that execute_simple_command uses, so each child inherits a fully-expanded argv. Compound stages (subshells etc.) are expanded later inside their own executor_execute call.
Subshell, Block, Background
Subshell, block, and background execution for 42sh.
- Author
wengzhang, pulgamecanica
Functions
-
int execute_subshell(t_shell *shell, t_ast *ast)
( cmd ) - runs in a forked child (subshell) with its own pgrp, routed through the job-control machinery so Ctrl-Z works.
-
int execute_block(t_shell *shell, t_ast *ast)
{ cmd; } - runs in the current shell, but with its own redirections.
-
static void bg_child(t_shell *shell, t_ast *ast)
Execute a background command.
cmd & - runs in a forked child with its own process group.
- Parameters:
shell – The shell instance.
ast – The abstract syntax tree node.
- Returns:
The exit status of the command.
-
static void bg_apply_assignments(t_shell *shell, t_list *assigns)
Apply (and export) inline assignments in a bg subshell child.
Equivalent to
apply_assignments(shell, ..., 1)in exec_command, inlined here because that helper isn’t exported and pulling it in would over-couple the modules.
-
static void bg_simple_child(t_shell *shell, t_ast *outer, t_cmd *cmd)
Child path for
simple-command &: fork once, exec directly.Bypasses the bg_child → executor_execute → exec_command → exec_child double-fork. That chain put the actual program in its own pgrp (not the job’s pgrp) and made exec_child call tcsetpgrp from a background pgrp — both broken. This single fork keeps the program in the same pgrp the parent tracks and never claims the terminal.
I/O Redirections
Redirection setup and restore for 42sh.
- Author
wengzhang, pulgamecanica
Functions
-
int setup_redirections(t_list *redirs, int saved_fds[3])
redirection setup
If saved_fds is not NULL, save stdin/stdout/stderr first (for restore).
-
void restore_redirections(int saved_fds[3])
Restore redirections.
- Parameters:
saved_fds – Array of saved file descriptors
PATH Lookup
Command search functionality for 42sh.
- Author
wengzhang, pulgamecanica
Functions
-
static char *build_path(const char *dir, const char *name)
Build “dir/name” path. Caller must free the result.
- Parameters:
dir – The directory path.
name – The file name.
- Returns:
The full path, or NULL if allocation fails.
-
static void free_split(char **arr)
Search each directory in PATH for an executable named
name.- Parameters:
path_var – The PATH environment variable.
name – The command name.
- Returns:
Heap-allocated full path, or NULL if not found.
-
static char *search_path(const char *path_var, const char *name)
Search each directory in PATH for an executable named
name.- Parameters:
path_var – The PATH environment variable.
name – The command name.
- Returns:
Heap-allocated full path, or NULL if not found.
-
static char *lookup_cached(t_shell *shell, const char *name)
Consult the command-path cache before walking PATH.
A cached path that no longer exists (file deleted, PATH changed, etc.) falls through to a fresh PATH walk. The hit counter is bumped only when the cache actually satisfies the lookup, so
hashreflects real usage rather than just insertions.
-
char *find_command(t_shell *shell, const char *name)
If name contains ‘/’, treat it as a path directly.
Otherwise consult the hash cache, then search $PATH and remember the result on hit so the next lookup is O(1).
-
int report_command_error(const char *name)
Print the diagnostic for an unrunnable command and return its exit status.
Print the diagnostic for an unrunnable command and return its exit status: 126 if the path exists but is not executable, 127 if it could not be found.
Distinguishes “exists but not executable” (126, permission denied) from “not found” (127). Only a name containing ‘/’ can be probed for existence on disk; a bare name that PATH search failed to resolve is reported as not found.
- Parameters:
name – The command name as typed.
- Returns:
126 if the path exists but is not executable, 127 otherwise.
Utilities
Utility functions for command execution in 42sh.
- Author
wengzhang, pulgamecanica
Functions
-
int get_exit_status(int wstatus)
get exit status from wait status
Normal exit: WEXITSTATUS (0-255)
Killed by signal: 128 + signal number
-
void split_assignment(const char *assign, char **name, char **value)
Caller must free both *name and *value.
If no ‘=’ found, *name = dup of assign, *value = dup of “”.