diff options
Diffstat (limited to 'src/eval/eval_exe.cc')
| -rw-r--r-- | src/eval/eval_exe.cc | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/src/eval/eval_exe.cc b/src/eval/eval_exe.cc new file mode 100644 index 0000000..534b878 --- /dev/null +++ b/src/eval/eval_exe.cc @@ -0,0 +1,159 @@ +#include "eval.h" + +#include <string> + +#include "error.h" +#include "lang_analysis/lexer_class.h" +#include "lang_analysis/ast.h" +#include "lang_analysis/token.h" +#include "lang_analysis/enum_type.h" +#include "lang_analysis/symbol_property.h" +#include "lang_analysis/parseline.h" +#include "util/io.h" + +using namespace std; + +extern char **environ; + +namespace ov4 +{ + +int eval_exe(const string &s, bool is_async) +{ + return eval_exe(s, is_async, nullptr, string::npos); +} + +int eval_exe(const string &s, bool is_async, const T_lexer *lexer_instance, size_t i) +{ + loggerln("eval_exe: receive {}", s); + + bool task_type_is_subshell = false; + const char *raw_input = nullptr; + char **argv = nullptr; + const char *unified_cmd_c = nullptr; + string unified_cmd, s_wrap_eliminated; + + // subshell type + if (lexer_instance != nullptr) + { + task_type_is_subshell = true; + unified_cmd = "SUBSHELL"; + raw_input = unified_cmd.c_str(); + } + // command type + else + { + task_type_is_subshell = false; + s_wrap_eliminated = s.substr(0, s.find('\n')); // eliminate \n + raw_input = s_wrap_eliminated.c_str(); + + // NB: remember to delete + argv = parseline(s); + + if (argv == nullptr || argv[0] == nullptr) { operator delete(argv); return 0; } + + if (exe_bultin_command(argv)) { operator delete(argv); return 0; } + + unified_cmd = find_cmd(argv[0]); + unified_cmd_c = unified_cmd.c_str(); + } + + // block_io signals can stop shell + // when child is at foreground, parent shell is at background + sigprocmask(SIG_BLOCK, &block_io, nullptr); + + sigset_t prev; + block_all(&prev); + + shell_pgid = getpgid(0); + pid_t pid = fork(); + + if (pid == 0) // child + { + setpgid(0, 0); + if (!is_async) // foreground + tcsetpgrp(tty_fd, getpgrp()); + + sigprocmask(SIG_SETMASK, &prev, nullptr); + + // program inside execve may use SIGTTIN/SIGTTOU + // so just restore in child + sigprocmask(SIG_UNBLOCK, &block_io, nullptr); + + // subshell + if (task_type_is_subshell) + { + eval_tree_cd(i, *lexer_instance, true); + exit(0); + } + + // normal command + execve(unified_cmd_c, argv, environ); + + // execve: if success, never returns + + cout << raw_input << flush; + switch (errno) + { + case ENOTDIR: + println(": A component of the path prefix is not a directory."); + _exit(errno); + break; + + case ENAMETOOLONG: + println(": A component of a pathname exceeded 255 characters, or an entire path name exceeded 1023 characters."); + _exit(errno); + break; + + case ENOENT: + println(": The new process file does not exist."); + _exit(errno); + break; + + case EACCES: + println(": The new process file mode denies execute permission."); + _exit(errno); + break; + + default: + println(": Error, code: {}", errno); + _exit(errno); + } + } + + // parent + + operator delete(argv); + argv = nullptr; + + exit_required_pid = pid; + + if (!is_async) // foreground + { + addjob(pid, FG, raw_input); + sigset_t prev_with_sigchld_blocked = prev; + sigaddset(&prev_with_sigchld_blocked, SIGCHLD); + sigprocmask(SIG_SETMASK, &prev_with_sigchld_blocked, NULL); + waitfg(pid); + sigprocmask(SIG_SETMASK, &prev, NULL); + + return exit_code; + } + else // background + { + addjob(pid, BG, raw_input); + sigprocmask(SIG_SETMASK, &prev, NULL); + cout << "[" << pid2jid(pid) << "] (" << pid << ") " << raw_input; + + // POSIX: + // async command returns 0 immediately + // TODO: recurring async + return 0; + } + + + + return 0; +} + +}
\ No newline at end of file |
