diff options
author | Itamar <itamar8910@gmail.com> | 2021-12-20 22:32:21 +0200 |
---|---|---|
committer | Brian Gianforcaro <b.gianfo@gmail.com> | 2021-12-22 02:14:32 -0800 |
commit | 0cea8d13105774939b2d08d019d1e7b9f6d4ae7d (patch) | |
tree | 8c263f0706b1968aeabf21568f9acdfe7d0a89e1 /Userland/DevTools | |
parent | 83dd1e5b801275dbad9f6171052f32db75f489d6 (diff) | |
download | serenity-0cea8d13105774939b2d08d019d1e7b9f6d4ae7d.zip |
HackStudio: Separate master & slave PTY setup in TerminalWrapper
Previously the setup for both the master and slave pseudoterminals was
done in TerminalWrapper::run_command.
This commit separates the relevant logic into
TerminalWrapper::setup_master_pseudoterminal
and TerminalWrapper::setup_slave_pseudoterminal.
Diffstat (limited to 'Userland/DevTools')
-rw-r--r-- | Userland/DevTools/HackStudio/TerminalWrapper.cpp | 173 | ||||
-rw-r--r-- | Userland/DevTools/HackStudio/TerminalWrapper.h | 8 |
2 files changed, 102 insertions, 79 deletions
diff --git a/Userland/DevTools/HackStudio/TerminalWrapper.cpp b/Userland/DevTools/HackStudio/TerminalWrapper.cpp index 57200c7ad5..1d1fd6433d 100644 --- a/Userland/DevTools/HackStudio/TerminalWrapper.cpp +++ b/Userland/DevTools/HackStudio/TerminalWrapper.cpp @@ -32,6 +32,44 @@ void TerminalWrapper::run_command(const String& command) return; } + auto ptm_res = setup_master_pseudoterminal(); + if (ptm_res.is_error()) { + perror("setup_master_pseudoterminal"); + return; + } + + int ptm_fd = ptm_res.value(); + + m_pid = fork(); + if (m_pid < 0) { + perror("fork"); + return; + } + + if (m_pid > 0) + return; + + if (setup_slave_pseudoterminal(ptm_fd).is_error()) { + perror("setup_pseudoterminal"); + exit(1); + } + + auto parts = command.split(' '); + VERIFY(!parts.is_empty()); + const char** args = (const char**)calloc(parts.size() + 1, sizeof(const char*)); + for (size_t i = 0; i < parts.size(); i++) { + args[i] = parts[i].characters(); + } + auto rc = execvp(args[0], const_cast<char**>(args)); + if (rc < 0) { + perror("execve"); + exit(1); + } + VERIFY_NOT_REACHED(); +} + +ErrorOr<int> TerminalWrapper::setup_master_pseudoterminal(WaitForChildOnExit wait_for_child) +{ int ptm_fd = posix_openpt(O_RDWR | O_CLOEXEC); if (ptm_fd < 0) { perror("posix_openpt"); @@ -47,19 +85,21 @@ void TerminalWrapper::run_command(const String& command) } m_terminal_widget->set_pty_master_fd(ptm_fd); - m_terminal_widget->on_command_exit = [this] { - int wstatus; - int rc = waitpid(m_pid, &wstatus, 0); - if (rc < 0) { - perror("waitpid"); - VERIFY_NOT_REACHED(); - } - if (WIFEXITED(wstatus)) { - m_terminal_widget->inject_string(String::formatted("\033[{};1m(Command exited with code {})\033[0m\r\n", wstatus == 0 ? 32 : 31, WEXITSTATUS(wstatus))); - } else if (WIFSTOPPED(wstatus)) { - m_terminal_widget->inject_string("\033[34;1m(Command stopped!)\033[0m\r\n"); - } else if (WIFSIGNALED(wstatus)) { - m_terminal_widget->inject_string(String::formatted("\033[34;1m(Command signaled with {}!)\033[0m\r\n", strsignal(WTERMSIG(wstatus)))); + m_terminal_widget->on_command_exit = [this, wait_for_child] { + if (wait_for_child == WaitForChildOnExit::Yes) { + int wstatus; + int rc = waitpid(m_pid, &wstatus, 0); + if (rc < 0) { + perror("waitpid"); + VERIFY_NOT_REACHED(); + } + if (WIFEXITED(wstatus)) { + m_terminal_widget->inject_string(String::formatted("\033[{};1m(Command exited with code {})\033[0m\r\n", wstatus == 0 ? 32 : 31, WEXITSTATUS(wstatus))); + } else if (WIFSTOPPED(wstatus)) { + m_terminal_widget->inject_string("\033[34;1m(Command stopped!)\033[0m\r\n"); + } else if (WIFSIGNALED(wstatus)) { + m_terminal_widget->inject_string(String::formatted("\033[34;1m(Command signaled with {}!)\033[0m\r\n", strsignal(WTERMSIG(wstatus)))); + } } m_pid = -1; @@ -67,81 +107,56 @@ void TerminalWrapper::run_command(const String& command) on_command_exit(); }; - m_pid = fork(); - if (m_pid < 0) { - perror("fork"); - return; - } + terminal().scroll_to_bottom(); - if (m_pid == 0) { - // Create a new process group. - setsid(); + return ptm_fd; +} - const char* tty_name = ptsname(ptm_fd); - if (!tty_name) { - perror("ptsname"); - exit(1); - } - close(ptm_fd); - int pts_fd = open(tty_name, O_RDWR); - if (pts_fd < 0) { - perror("open"); - exit(1); - } +ErrorOr<void> TerminalWrapper::setup_slave_pseudoterminal(int master_fd) +{ + setsid(); - tcsetpgrp(pts_fd, getpid()); + const char* tty_name = ptsname(master_fd); + if (!tty_name) + return Error::from_errno(errno); - // NOTE: It's okay if this fails. - int rc = ioctl(0, TIOCNOTTY); + close(master_fd); + int pts_fd = open(tty_name, O_RDWR); + if (pts_fd < 0) + return Error::from_errno(errno); - close(0); - close(1); - close(2); + tcsetpgrp(pts_fd, getpid()); - rc = dup2(pts_fd, 0); - if (rc < 0) { - perror("dup2"); - exit(1); - } - rc = dup2(pts_fd, 1); - if (rc < 0) { - perror("dup2"); - exit(1); - } - rc = dup2(pts_fd, 2); - if (rc < 0) { - perror("dup2"); - exit(1); - } - rc = close(pts_fd); - if (rc < 0) { - perror("close"); - exit(1); - } - rc = ioctl(0, TIOCSCTTY); - if (rc < 0) { - perror("ioctl(TIOCSCTTY)"); - exit(1); - } + // NOTE: It's okay if this fails. + int rc = ioctl(0, TIOCNOTTY); - setenv("TERM", "xterm", true); + close(0); + close(1); + close(2); - auto parts = command.split(' '); - VERIFY(!parts.is_empty()); - const char** args = (const char**)calloc(parts.size() + 1, sizeof(const char*)); - for (size_t i = 0; i < parts.size(); i++) { - args[i] = parts[i].characters(); - } - rc = execvp(args[0], const_cast<char**>(args)); - if (rc < 0) { - perror("execve"); - exit(1); - } - VERIFY_NOT_REACHED(); - } + rc = dup2(pts_fd, 0); + if (rc < 0) + return Error::from_errno(errno); - // (In parent process) - terminal().scroll_to_bottom(); + rc = dup2(pts_fd, 1); + if (rc < 0) + return Error::from_errno(errno); + + rc = dup2(pts_fd, 2); + if (rc < 0) + return Error::from_errno(errno); + + rc = close(pts_fd); + if (rc < 0) + return Error::from_errno(errno); + + rc = ioctl(0, TIOCSCTTY); + if (rc < 0) + return Error::from_errno(errno); + + setenv("TERM", "xterm", true); + + return {}; } void TerminalWrapper::kill_running_command() diff --git a/Userland/DevTools/HackStudio/TerminalWrapper.h b/Userland/DevTools/HackStudio/TerminalWrapper.h index 7ce260a116..9918f9335b 100644 --- a/Userland/DevTools/HackStudio/TerminalWrapper.h +++ b/Userland/DevTools/HackStudio/TerminalWrapper.h @@ -6,6 +6,7 @@ #pragma once +#include <AK/Error.h> #include <LibGUI/Widget.h> #include <LibVT/TerminalWidget.h> @@ -23,6 +24,13 @@ public: bool user_spawned() const { return m_user_spawned; } VT::TerminalWidget& terminal() { return *m_terminal_widget; } + enum class WaitForChildOnExit { + No, + Yes, + }; + ErrorOr<int> setup_master_pseudoterminal(WaitForChildOnExit = WaitForChildOnExit::Yes); + static ErrorOr<void> setup_slave_pseudoterminal(int master_fd); + Function<void()> on_command_exit; private: |