summaryrefslogtreecommitdiff
path: root/Userland/DevTools
diff options
context:
space:
mode:
authorItamar <itamar8910@gmail.com>2021-12-20 22:32:21 +0200
committerBrian Gianforcaro <b.gianfo@gmail.com>2021-12-22 02:14:32 -0800
commit0cea8d13105774939b2d08d019d1e7b9f6d4ae7d (patch)
tree8c263f0706b1968aeabf21568f9acdfe7d0a89e1 /Userland/DevTools
parent83dd1e5b801275dbad9f6171052f32db75f489d6 (diff)
downloadserenity-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.cpp173
-rw-r--r--Userland/DevTools/HackStudio/TerminalWrapper.h8
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: