#include #include #include #include #include #include "syntax.h" #include "utils.h" void execute_command_pipeline(Pipeline pipeline, int stdin_fd, int stdout_fd); void execute_cmd(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.redirects.count; i++) { FdRedirect fd_rd = *get_from_FdRedirectVec(&cmd.redirects, i); dup2(fd_rd.to, fd_rd.redirected); } for (int j = 0; j < cmd.child_open_fds.count; j++) { int fd = *get_from_IntVec(&cmd.child_open_fds, j); close(fd); } 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); } } ExecutableCommand process_pl_command(PlCommand pl_cmd) { StrVec arg_vec = make_StrVec(256); FdRedirectVec fd_redirs = make_FdRedirectVec(256); IntVec parent_open_fds = make_IntVec(256); IntVec child_open_fds = make_IntVec(256); int ps_pipe_fds[2]; for (int i = 0; i < pl_cmd.args.count; i++) { Arg arg = *get_from_ArgVec(&pl_cmd.args, i); switch (arg.kind) { case ARG_LIT: push_to_StrVec(&arg_vec, arg.as.lit_str); break; case ARG_PS_IN: pipe(ps_pipe_fds); execute_command_pipeline(*(Pipeline*)arg.as.sub_pipeline, STDIN_FILENO, ps_pipe_fds[1]); close(ps_pipe_fds[1]); char pname[64]; snprintf(pname, sizeof(pname), "/dev/fd/%d", ps_pipe_fds[0]); push_to_IntVec(&parent_open_fds, ps_pipe_fds[0]); push_to_StrVec(&arg_vec, strdup(pname)); break; default: exit(67); } } for (int j = 0; j < pl_cmd.redirects.count; j++) { Redirect redir = *get_from_RedirectVec(&pl_cmd.redirects, j); FdRedirect fd_redir; int fd; switch (redir.kind) { case REDIR_READ: fd = open(redir.as.filename, O_RDONLY, 0644); push_to_IntVec(&parent_open_fds, fd); push_to_IntVec(&child_open_fds, fd); fd_redir = (FdRedirect){.to = fd, .redirected = STDIN_FILENO}; break; case REDIR_WRITE_APPEND: fd = open(redir.as.filename, O_WRONLY | O_CREAT | O_APPEND, 0644); push_to_IntVec(&parent_open_fds, fd); push_to_IntVec(&child_open_fds, fd); fd_redir = (FdRedirect){.to = fd, .redirected = STDOUT_FILENO}; break; case REDIR_WRITE_TRUNC: fd = open(redir.as.filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); push_to_IntVec(&parent_open_fds, fd); push_to_IntVec(&child_open_fds, fd); fd_redir = (FdRedirect){.to = fd, .redirected = STDOUT_FILENO}; break; default: exit(67); } push_to_FdRedirectVec(&fd_redirs, fd_redir); } char** args = malloc(sizeof(char*) * (arg_vec.count + 1)); for (int i = 0; i < arg_vec.count; i++) { args[i] = *get_from_StrVec(&arg_vec, i); } args[arg_vec.count] = NULL; return (ExecutableCommand){.args = args, .redirects = fd_redirs, .parent_open_fds = parent_open_fds, .child_open_fds = child_open_fds}; } void execute_command_pipeline(Pipeline pipeline, int stdin_fd, int stdout_fd) { int trunk_fd = stdin_fd; int pgid = -1; for (int i = 0; i < pipeline.count; i++) { PlCommand cmd = *get_from_Pipeline(&pipeline, i); ExecutableCommand exec_cmd = process_pl_command(cmd); exec_cmd.stdin_fd = trunk_fd; if (i > 0) { push_to_IntVec(&exec_cmd.parent_open_fds, trunk_fd); push_to_IntVec(&exec_cmd.child_open_fds, trunk_fd); } exec_cmd.stdout_fd = stdout_fd; if (cmd.conn == CONN_PIPE) { int pipe_fds[2]; pipe(pipe_fds); exec_cmd.stdout_fd = pipe_fds[1]; push_to_IntVec(&exec_cmd.parent_open_fds, pipe_fds[1]); push_to_IntVec(&exec_cmd.child_open_fds, pipe_fds[1]); trunk_fd = pipe_fds[0]; } execute_cmd(exec_cmd, &pgid); for (int j = 0; j < exec_cmd.parent_open_fds.count; j++) { int fd = *get_from_IntVec(&exec_cmd.parent_open_fds, j); close(fd); } } tcsetpgrp(STDIN_FILENO, pgid); while (waitpid(-pgid, NULL, 0) > 0); tcsetpgrp(STDIN_FILENO, getpgrp()); } void execute_pipeline_tree(PipelineTree pltree) { signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); execute_command_pipeline(*pltree.root, STDIN_FILENO, STDOUT_FILENO); }