Terminal: Use pseudo terminal instead of pipes

Terminal can now send signals from keyboard (ctrl+c) to programs running
in the terminal!
This commit is contained in:
Bananymous 2024-08-11 01:01:05 +03:00
parent 4d1b32f770
commit 9e79ef2a91
2 changed files with 34 additions and 42 deletions

View File

@ -4,59 +4,63 @@
#include <BAN/UTF8.h> #include <BAN/UTF8.h>
#include <ctype.h> #include <ctype.h>
#include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/select.h> #include <sys/select.h>
#include <unistd.h> #include <unistd.h>
void Terminal::start_shell() void Terminal::start_shell()
{ {
int shell_stdin[2]; int pts_master = posix_openpt(O_RDWR | O_NOCTTY);
if (pipe(shell_stdin) == -1) if (pts_master == -1)
{ {
dwarnln("pipe: {}", strerror(errno)); dwarnln("posix_openpt: {}", strerror(errno));
exit(1); exit(1);
} }
int shell_stdout[2]; if (grantpt(pts_master) == -1)
if (pipe(shell_stdout) == -1)
{ {
dwarnln("pipe: {}", strerror(errno)); dwarnln("grantpt: {}", strerror(errno));
exit(1); exit(1);
} }
int shell_stderr[2]; if (unlockpt(pts_master) == -1)
if (pipe(shell_stderr) == -1)
{ {
dwarnln("pipe: {}", strerror(errno)); dwarnln("unlockpt: {}", strerror(errno));
exit(1); exit(1);
} }
pid_t shell_pid = fork(); pid_t shell_pid = fork();
if (shell_pid == 0) if (shell_pid == 0)
{ {
if (dup2(shell_stdin[0], STDIN_FILENO) == -1) if (setsid() == -1)
{ {
dwarnln("dup2: {}", strerror(errno)); dwarnln("setsid: {}", strerror(errno));
exit(1); exit(1);
} }
close(shell_stdin[0]);
close(shell_stdin[1]);
if (dup2(shell_stdout[1], STDOUT_FILENO) == -1) char* pts_slave_name = ptsname(pts_master);
if (pts_slave_name == nullptr)
{ {
dwarnln("dup2: {}", strerror(errno)); dwarnln("ptsname: {}", strerror(errno));
exit(1); exit(1);
} }
close(shell_stdout[0]);
close(shell_stdout[1]);
if (dup2(shell_stderr[1], STDERR_FILENO) == -1) int pts_slave = open(pts_slave_name, O_RDWR);
if (pts_slave == -1)
{
dwarnln("open: {}", strerror(errno));
exit(1);
}
if (dup2(pts_slave, STDIN_FILENO) == -1 || dup2(pts_slave, STDOUT_FILENO) == -1 || dup2(pts_slave, STDERR_FILENO) == -1)
{ {
dwarnln("dup2: {}", strerror(errno)); dwarnln("dup2: {}", strerror(errno));
exit(1); exit(1);
} }
close(shell_stderr[0]);
close(shell_stderr[1]); close(pts_slave);
close(pts_master);
execl("/bin/Shell", "Shell", NULL); execl("/bin/Shell", "Shell", NULL);
exit(1); exit(1);
@ -68,14 +72,8 @@ void Terminal::start_shell()
exit(1); exit(1);
} }
close(shell_stdin[0]);
close(shell_stdout[1]);
close(shell_stderr[1]);
m_shell_info = { m_shell_info = {
.in = shell_stdin[1], .pts_master = pts_master,
.out = shell_stdout[0],
.err = shell_stderr[0],
.pid = shell_pid .pid = shell_pid
}; };
} }
@ -95,22 +93,18 @@ void Terminal::run()
m_window->set_key_event_callback([&](LibGUI::EventPacket::KeyEvent event) { on_key_event(event); }); m_window->set_key_event_callback([&](LibGUI::EventPacket::KeyEvent event) { on_key_event(event); });
const int max_fd = BAN::Math::max(BAN::Math::max(m_shell_info.out, m_shell_info.err), m_window->server_fd()); const int max_fd = BAN::Math::max(m_shell_info.pts_master, m_window->server_fd());
while (!s_shell_exited) while (!s_shell_exited)
{ {
fd_set fds; fd_set fds;
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(m_shell_info.out, &fds); FD_SET(m_shell_info.pts_master, &fds);
FD_SET(m_shell_info.err, &fds);
FD_SET(m_window->server_fd(), &fds); FD_SET(m_window->server_fd(), &fds);
select(max_fd + 1, &fds, nullptr, nullptr, nullptr); select(max_fd + 1, &fds, nullptr, nullptr, nullptr);
if (FD_ISSET(m_shell_info.out, &fds)) if (FD_ISSET(m_shell_info.pts_master, &fds))
if (!read_shell(m_shell_info.out)) if (!read_shell())
break;
if (FD_ISSET(m_shell_info.err, &fds))
if (!read_shell(m_shell_info.err))
break; break;
if (FD_ISSET(m_window->server_fd(), &fds)) if (FD_ISSET(m_window->server_fd(), &fds))
m_window->poll_events(); m_window->poll_events();
@ -118,10 +112,10 @@ void Terminal::run()
} }
bool Terminal::read_shell(int fd) bool Terminal::read_shell()
{ {
char buffer[128]; char buffer[128];
ssize_t nread = read(fd, buffer, sizeof(buffer) - 1); ssize_t nread = read(m_shell_info.pts_master, buffer, sizeof(buffer) - 1);
if (nread < 0) if (nread < 0)
dwarnln("read: {}", strerror(errno)); dwarnln("read: {}", strerror(errno));
if (nread <= 0) if (nread <= 0)
@ -409,5 +403,5 @@ void Terminal::on_key_event(LibGUI::EventPacket::KeyEvent event)
if (event.released()) if (event.released())
return; return;
if (const char* text = LibInput::key_to_utf8_ansi(event.key, event.modifier)) if (const char* text = LibInput::key_to_utf8_ansi(event.key, event.modifier))
write(m_shell_info.in, text, strlen(text)); write(m_shell_info.pts_master, text, strlen(text));
} }

View File

@ -16,7 +16,7 @@ private:
void handle_csi(char ch); void handle_csi(char ch);
void handle_sgr(); void handle_sgr();
void putchar(uint8_t ch); void putchar(uint8_t ch);
bool read_shell(int fd); bool read_shell();
void on_key_event(LibGUI::EventPacket::KeyEvent); void on_key_event(LibGUI::EventPacket::KeyEvent);
@ -31,9 +31,7 @@ private:
struct ShellInfo struct ShellInfo
{ {
int in; int pts_master;
int out;
int err;
pid_t pid; pid_t pid;
}; };