#include #include #include #include #include #include #include "utils.h" #include "exec.h" #include "preproc.h" char* get_var(char* varname, ShellState* shstate) { MaybeStr maybe_varval = get_map_value(&shstate->shell_vars, varname); if (maybe_varval.some == true) return maybe_varval.value; return getenv(varname); } typedef struct { QuotationMode qmode; char* content; } ExpandedChunk; ExpandedChunk expand_chunk(Chunk chunk, ShellState* shstate) { char* content; if (chunk.qmode == SINGLE_Q || chunk.kind == LITERAL) { if (chunk.qmode == SINGLE_Q && chunk.kind != LITERAL) exit(69); content = chunk.as.literal_str; } else if (chunk.kind == VAR_EXP) { content = get_var(chunk.as.varname, shstate); } else if (chunk.kind == REGION_EXP) { exit(7); // Not supported yet; arithm } return (ExpandedChunk){.qmode = chunk.qmode, .content = content}; } typedef struct { StrVec complete_strs; String active_str; } WordSplittingGerm; void add_expchunk(char* next_str, WordSplittingGerm* curr_res) { for (int pos = 0; pos < strlen(next_str); pos++) { if (next_str[pos] == ' ') { push_to_StrVec(&curr_res->complete_strs, inner(&curr_res->active_str)); curr_res->active_str = make_String(256); } else { push_to_String(&curr_res->active_str, next_str[pos]); } } } StrVec expand_word(Word word, ShellState* state) { WordSplittingGerm curr_res = {.complete_strs = make_StrVec(256), .active_str = make_String(25)}; for (int i = 0; i < word.count; i++) { Chunk curr_cunk = **get_from_Word(&word, i); ExpandedChunk curr_exp = expand_chunk(curr_cunk, state); switch (curr_exp.qmode) { case UN_Q: add_expchunk(curr_exp.content, &curr_res); break; case SINGLE_Q: append_str_to_String(&curr_res.active_str, curr_exp.content); break; case DOUBLE_Q: append_str_to_String(&curr_res.active_str, curr_exp.content); } } if (curr_res.active_str.count > 0) { push_to_StrVec(&curr_res.complete_strs, inner(&curr_res.active_str)); } return curr_res.complete_strs; } void merge_strvecs(StrVec* target, StrVec* source) { for (int i = 0; i < source->count; i++) { push_to_StrVec(target, *get_from_StrVec(source, i)); } } char** make_cmd_args(Command command, ShellState* shstate) { StrVec arg_str_vec = make_StrVec(256); for (int i = 0; i < command.args.count; i++) { Token arg_i = *get_from_TokenVec(&command.args, i); StrVec expanded_i; switch (arg_i.kind) { case TOK_WORD: expanded_i = expand_word(arg_i.as.word, shstate); merge_strvecs(&arg_str_vec, &expanded_i); break; default: exit(67); } } int argcount = arg_str_vec.count; char** arg_str_arr = malloc(sizeof(char*) * (argcount + 1)); for (int j = 0; j < argcount; j++) { arg_str_arr[j] = *get_from_StrVec(&arg_str_vec, j); } arg_str_arr[argcount] = NULL; return arg_str_arr; } typedef struct { char** args; int stdin_fd; int stdout_fd; IntVec child_close_fds; IntVec parent_close_fds; } ExecutableCommand; void execute_command(ExecutableCommand cmd, int* pgid) { pid_t pid = fork(); if (pid == 0) { if (*pgid == -1) { setpgid(0, 0); } else { setpgid(0, *pgid); } dup2(cmd.stdin_fd, STDIN_FILENO); dup2(cmd.stdout_fd, STDOUT_FILENO); for (int i = 0; i < cmd.child_close_fds.count; i++) { close(*get_from_IntVec(&cmd.child_close_fds, i)); } signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGTSTP, SIG_DFL); signal(SIGTTIN, SIG_DFL); signal(SIGTTOU, SIG_DFL); execvp(cmd.args[0], cmd.args); exit(67); } if (*pgid == -1) { setpgid(pid, pid); *pgid = pid; } else { setpgid(pid, *pgid); } } void run_pipeline(Pipeline pl, ShellState* shstate) { signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); int last_pipe_fd; int pgid = -1; for (int i = 0; i < pl.count; i++) { PipelineElement elem = *get_from_Pipeline(&pl, i); ExecutableCommand cmd = {.child_close_fds = make_IntVec(64), .parent_close_fds = make_IntVec(64)}; cmd.args = make_cmd_args(elem.cmd, shstate); if (i == 0) { cmd.stdin_fd = STDIN_FILENO; } else { cmd.stdin_fd = last_pipe_fd; push_to_IntVec(&cmd.child_close_fds, last_pipe_fd); push_to_IntVec(&cmd.parent_close_fds, last_pipe_fd); } if (elem.conn == CONN_PIPE) { int pipe_fds[2]; pipe(pipe_fds); cmd.stdout_fd = pipe_fds[1]; push_to_IntVec(&cmd.child_close_fds, pipe_fds[1]); push_to_IntVec(&cmd.parent_close_fds, pipe_fds[1]); last_pipe_fd = pipe_fds[0]; } else { cmd.stdout_fd = STDOUT_FILENO; } execute_command(cmd, &pgid); for (int j = 0; j < cmd.parent_close_fds.count; j++) { close(*get_from_IntVec(&cmd.parent_close_fds, j)); } } tcsetpgrp(STDIN_FILENO, pgid); while (waitpid(-pgid, NULL, 0) > 0); tcsetpgrp(STDIN_FILENO, getpgrp()); }