From e489a2db5a1e56e66f6df12642ad8cfd988d4b30 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Wed, 16 Sep 2026 11:28:14 +0000 Subject: implement subshell, and fix vector operator[] unvalid index --- src/eval.cc | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 6 deletions(-) (limited to 'src/eval.cc') diff --git a/src/eval.cc b/src/eval.cc index 0192ab7..6d16cf7 100644 --- a/src/eval.cc +++ b/src/eval.cc @@ -30,7 +30,7 @@ extern char **environ; namespace ov4 { -int eval_exe(string s, bool is_aync) +int eval_exe(const string &s, bool is_aync) { loggerln("eval_exe: receive {}", s); @@ -69,10 +69,13 @@ int eval_exe(string s, bool is_aync) sigprocmask(SIG_SETMASK, &prev, nullptr); - // program inside execve may use SIGTTIN/SIGTTOU so just restore in child + // program inside execve may use SIGTTIN/SIGTTOU + // so just restore in child sigprocmask(SIG_UNBLOCK, &block_io, nullptr); execve(cmd_c, argv, environ); + // execve: if success, never returns + wrap_eliminator(cmdline); cout << cmdline << flush; switch (errno) @@ -135,12 +138,85 @@ int eval_exe(string s, bool is_aync) return 0; } -int eval_tree_cd(size_t i, const T_lexer &lexer_instance) +int eval_subshell(size_t i, const T_lexer &lexer_instance) +{ + println("eval_tree_cd: processing subshell"); + + // TODO: implement async + bool is_aync = false; + + char cmdline[] = "subshell"; + + // 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_aync) // 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); + eval_tree_cd(i, lexer_instance, true); + exit(0); + } + + // parent + + exit_required_pid = pid; + + if (!is_aync) // foreground + { + addjob(pid, FG, cmdline); + 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, cmdline); + sigprocmask(SIG_SETMASK, &prev, NULL); + cout << "[" << pid2jid(pid) << "] (" << pid << ") " << cmdline; + + // POSIX: + // async command returns 0 immediately + // TODO: recurring async + return 0; + } +} + +int eval_tree_cd(size_t i, const T_lexer &lexer_instance, bool inside_subshell) { // TODO: async int ret = -1; + println("eval_tree_cd: processing {} subshell {}", i, (lexer_instance.ast[i].subshell ? "TRUE" : "FALSE")); + + // if it's a subshell, and current AST's subshell status is not subshell + // (subshell should be forkerd already, then set inside_subshell = true) + // fork itself + if (lexer_instance.ast[i].subshell && !inside_subshell) + { + eval_subshell(i, lexer_instance); + return 0; + } + if (lexer_instance.ast[i].token_type == TEXT) { ret = eval_exe(lexer_instance.ast[i].command_text, false); @@ -149,7 +225,7 @@ int eval_tree_cd(size_t i, const T_lexer &lexer_instance) if (lexer_instance.ast[i].left != string::npos) { - ret = eval_tree_cd(lexer_instance.ast[i].left, lexer_instance); + ret = eval_tree_cd(lexer_instance.ast[i].left, lexer_instance, false); } if (lexer_instance.ast[i].right != string::npos) @@ -157,7 +233,7 @@ int eval_tree_cd(size_t i, const T_lexer &lexer_instance) if (lexer_instance.ast[i].token_type == LOGIC_AND && ret != 0) return ret; if (lexer_instance.ast[i].token_type == LOGIC_OR && ret == 0) return ret; - ret = eval_tree_cd(lexer_instance.ast[i].right, lexer_instance); + ret = eval_tree_cd(lexer_instance.ast[i].right, lexer_instance, false); } return ret; } @@ -190,7 +266,7 @@ void eval(char *cmdline) return; } - eval_tree_cd(0, lexer_instance); + eval_tree_cd(0, lexer_instance, false); return; } -- cgit v1.3.1-4-g156e