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:
		
							parent
							
								
									4d1b32f770
								
							
						
					
					
						commit
						9e79ef2a91
					
				|  | @ -4,59 +4,63 @@ | |||
| #include <BAN/UTF8.h> | ||||
| 
 | ||||
| #include <ctype.h> | ||||
| #include <fcntl.h> | ||||
| #include <stdlib.h> | ||||
| #include <sys/select.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| void Terminal::start_shell() | ||||
| { | ||||
| 	int shell_stdin[2]; | ||||
| 	if (pipe(shell_stdin) == -1) | ||||
| 	int pts_master = posix_openpt(O_RDWR | O_NOCTTY); | ||||
| 	if (pts_master == -1) | ||||
| 	{ | ||||
| 		dwarnln("pipe: {}", strerror(errno)); | ||||
| 		dwarnln("posix_openpt: {}", strerror(errno)); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 
 | ||||
| 	int shell_stdout[2]; | ||||
| 	if (pipe(shell_stdout) == -1) | ||||
| 	if (grantpt(pts_master) == -1) | ||||
| 	{ | ||||
| 		dwarnln("pipe: {}", strerror(errno)); | ||||
| 		dwarnln("grantpt: {}", strerror(errno)); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 
 | ||||
| 	int shell_stderr[2]; | ||||
| 	if (pipe(shell_stderr) == -1) | ||||
| 	if (unlockpt(pts_master) == -1) | ||||
| 	{ | ||||
| 		dwarnln("pipe: {}", strerror(errno)); | ||||
| 		dwarnln("unlockpt: {}", strerror(errno)); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 
 | ||||
| 	pid_t shell_pid = fork(); | ||||
| 	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); | ||||
| 		} | ||||
| 		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); | ||||
| 		} | ||||
| 		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)); | ||||
| 			exit(1); | ||||
| 		} | ||||
| 		close(shell_stderr[0]); | ||||
| 		close(shell_stderr[1]); | ||||
| 
 | ||||
| 		close(pts_slave); | ||||
| 		close(pts_master); | ||||
| 
 | ||||
| 		execl("/bin/Shell", "Shell", NULL); | ||||
| 		exit(1); | ||||
|  | @ -68,14 +72,8 @@ void Terminal::start_shell() | |||
| 		exit(1); | ||||
| 	} | ||||
| 
 | ||||
| 	close(shell_stdin[0]); | ||||
| 	close(shell_stdout[1]); | ||||
| 	close(shell_stderr[1]); | ||||
| 
 | ||||
| 	m_shell_info = { | ||||
| 		.in = shell_stdin[1], | ||||
| 		.out = shell_stdout[0], | ||||
| 		.err = shell_stderr[0], | ||||
| 		.pts_master = pts_master, | ||||
| 		.pid = shell_pid | ||||
| 	}; | ||||
| } | ||||
|  | @ -95,22 +93,18 @@ void Terminal::run() | |||
| 
 | ||||
| 	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) | ||||
| 	{ | ||||
| 		fd_set fds; | ||||
| 		FD_ZERO(&fds); | ||||
| 		FD_SET(m_shell_info.out, &fds); | ||||
| 		FD_SET(m_shell_info.err, &fds); | ||||
| 		FD_SET(m_shell_info.pts_master, &fds); | ||||
| 		FD_SET(m_window->server_fd(), &fds); | ||||
| 
 | ||||
| 		select(max_fd + 1, &fds, nullptr, nullptr, nullptr); | ||||
| 
 | ||||
| 		if (FD_ISSET(m_shell_info.out, &fds)) | ||||
| 			if (!read_shell(m_shell_info.out)) | ||||
| 				break; | ||||
| 		if (FD_ISSET(m_shell_info.err, &fds)) | ||||
| 			if (!read_shell(m_shell_info.err)) | ||||
| 		if (FD_ISSET(m_shell_info.pts_master, &fds)) | ||||
| 			if (!read_shell()) | ||||
| 				break; | ||||
| 		if (FD_ISSET(m_window->server_fd(), &fds)) | ||||
| 			m_window->poll_events(); | ||||
|  | @ -118,10 +112,10 @@ void Terminal::run() | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool Terminal::read_shell(int fd) | ||||
| bool Terminal::read_shell() | ||||
| { | ||||
| 	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) | ||||
| 		dwarnln("read: {}", strerror(errno)); | ||||
| 	if (nread <= 0) | ||||
|  | @ -409,5 +403,5 @@ void Terminal::on_key_event(LibGUI::EventPacket::KeyEvent event) | |||
| 	if (event.released()) | ||||
| 		return; | ||||
| 	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)); | ||||
| } | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ private: | |||
| 	void handle_csi(char ch); | ||||
| 	void handle_sgr(); | ||||
| 	void putchar(uint8_t ch); | ||||
| 	bool read_shell(int fd); | ||||
| 	bool read_shell(); | ||||
| 
 | ||||
| 	void on_key_event(LibGUI::EventPacket::KeyEvent); | ||||
| 
 | ||||
|  | @ -31,9 +31,7 @@ private: | |||
| 
 | ||||
| 	struct ShellInfo | ||||
| 	{ | ||||
| 		int in; | ||||
| 		int out; | ||||
| 		int err; | ||||
| 		int pts_master; | ||||
| 		pid_t pid; | ||||
| 	}; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue