// Copyright (C) 2023, Jakob Wakeling // All rights reserved. #include "bltn.h" #include "exec.h" #include "parse.h" #include "util/log.h" #include "util/util.h" #include #include #include #include #include #include #include #include s32 _ret; static s32 execute_comm(ast *a, int fdi, int fd[2]); static s32 execute_pipe(ast *a, int fdi, int fd[2]); /* Execute a program. */ s32 execute(ast *a, int fdi, int fd[2]) { switch (a->k) { case AK_COMM: {} return execute_comm(a, fdi, fd); case AK_PIPE: {} return execute_pipe(a, fdi, fd); default: { log_warn("Unhandled AST kind \"%s\"", ast_ks[a->k]); } return -1; } } /* Execute a command statement. */ static s32 execute_comm(ast *a, int fdi, int fd[2]) { /* If the command is null, then do nothing */ if (!a->s) { return _ret; } /* Handle builtins */ for (bltn *b = bltns; b->name; b += 1) { if (strcmp(a->s, b->name) == 0) { return b->fn(a->c.al - 1, a->c.a); } } pid_t pid; int status, rin = -1, rout = -1, rerr = -1; /* Open redirect files. */ if (a->rin.s && (rin = open(a->rin.s, O_RDONLY)) == -1) { log_warn("%s: %s", a->rin.s, strerror(errno)); return -1; } if (a->rout.s && (rout = open(a->rout.s, O_WRONLY | O_CREAT | (a->rout.app ? O_APPEND : O_TRUNC), 0666)) == -1) { if (rin != -1) { close(rin); } log_warn("%s: %s", a->rout.s, strerror(errno)); return -1; } if (a->rerr.s && (rerr = open(a->rerr.s, O_WRONLY | O_CREAT | (a->rerr.app ? O_APPEND : O_TRUNC), 0666)) == -1) { if (rin != -1) { close(rin); } if (rout != -1) { close(rout); } log_warn("%s: %s", a->rerr.s, strerror(errno)); return -1; } char **av = a->c.a; /* Fork and exec the child process */ if ((pid = fork()) == 0) { signal(SIGINT, SIG_DFL); if (rin != -1) { dup2(rin, STDIN_FILENO); } else { dup2(fdi, STDIN_FILENO); } if (rout != -1) { dup2(rout, STDOUT_FILENO); } else if (fd) { dup2(fd[1], STDOUT_FILENO); } if (fd && fd[0]) { close(fd[0]); } if (rerr != -1) { dup2(rerr, STDERR_FILENO); } if (execvp((char *)av[0], (char **)av) == -1) { if (errno == ENOENT) { log_warn("%s: Command not found", av[0]); } else { perror((char *)av[0]); } exit(1); } } else if (pid == -1) { perror((char *)av[0]); } else { if (rout == -1 && fd) { if (fdi != STDIN_FILENO) { close(fdi); } close(fd[1]); } else { if (fd) { close(fd[1]); } waitpid(pid, &status, 0); } } if (rin != -1) { close(rin); } if (rout != -1) { close(rout); } if (rerr != -1) { close(rerr); } return WEXITSTATUS(status); } static s32 execute_pipe(ast *a, int fdi, int fd[2]) { int pd[2]; if (pipe(pd) == -1) { log_warn("PIPE: %s", strerror(errno)); return -1; } execute(a->lc, fdi, pd); return execute(a->rc, pd[0], fd); }