1. Your shell forks multiple child processes when executing piped commands. How does your implementation ensure that all child processes complete before the shell continues accepting user input? What would happen if you forgot to call waitpid() on all child processes?
_answer here_
>The parent process in `execute_pipeline` ensures all child processes complete before resuming with:
```c
for(inti=0;i<num_cmds;i++){
waitpid(pids[i],NULL,0);// Wait for all children
}
```
> Consequences of skipping `waitpid()`:
> Zombie processes: Child processes remain in the process table, leaking resources.
> I/O corruption: The shell prompt may print before child outputs finish, e.g., `running sleep 2 | echo "hello"` would show the prompt immediately, while hello appears later, overlapping with user input.
2. The dup2() function is used to redirect input and output file descriptors. Explain why it is necessary to close unused pipe ends after calling dup2(). What could go wrong if you leave pipes open?
_answer here_
> After dup2(), unused pipe ends are closed in child processes:
```c
if(i>0){
dup2(prev_pipe,STDIN_FILENO);
close(prev_pipe);// Close original FD after redirection
> Deadlocks: Open write FDs prevent readers from detecting EOF. For example, if a parent doesn’t close its write FD, the child process reading from the pipe will block indefinitely.
3. Your shell recognizes built-in commands (cd, exit, dragon). Unlike external commands, built-in commands do not require execvp(). Why is cd implemented as a built-in rather than an external command? What challenges would arise if cd were implemented as an external process?
_answer here_
> Process isolation: External commands run in child processes; their directory changes don’t propagate to the parent shell.
> Challenges for external cd:
> No effect: The shell’s working directory remains unchanged, making cd functionally useless.
> Workarounds: Would require complex IPC (e.g., signaling or shared memory) to sync directories, adding significant overhead.
4. Currently, your shell supports a fixed number of piped commands (CMD_MAX). How would you modify your implementation to allow an arbitrary number of piped commands while still handling memory allocation efficiently? What trade-offs would you need to consider?
_answer here_
> Replace the static array with a dynamic array to support on-demand expansion.