Terminal
This commit is contained in:
165
modules/Terminal/src/Terminal.cpp
Normal file
165
modules/Terminal/src/Terminal.cpp
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
#define _XOPEN_SOURCE 600
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
//#include <stdio.h>
|
||||||
|
#define __USE_BSD
|
||||||
|
#include <termios.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "Terminal.h"
|
||||||
|
#include "modules/ImguiModule/src/ImguiModule.h"
|
||||||
|
|
||||||
|
|
||||||
|
Terminal::Terminal(Archimedes::App* a, void* h) : Archimedes::Module(a, h) {
|
||||||
|
|
||||||
|
name = "Terminal";
|
||||||
|
|
||||||
|
ImguiModule* im = new ImguiModule(a, nullptr);
|
||||||
|
deps[im->getName()] = im;
|
||||||
|
}
|
||||||
|
|
||||||
|
Terminal::~Terminal() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Terminal::onLoad() {
|
||||||
|
|
||||||
|
ImguiModule* im = (ImguiModule*) moduleInstances["ImguiModule"];
|
||||||
|
|
||||||
|
if(!im) {
|
||||||
|
std::cout << "No ImguiModule for Terminal!\n";
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SetCurrentContext(im->getContext());
|
||||||
|
|
||||||
|
master = posix_openpt(O_RDWR);
|
||||||
|
if (master < 0) {
|
||||||
|
std::cerr << "Error " << errno << " on posix_openpt()\n";
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
int returnCode = grantpt(master);
|
||||||
|
if (!returnCode) {
|
||||||
|
std::cerr << "Error " << errno << " on grantpt()\n";
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
returnCode = unlockpt(master);
|
||||||
|
if (!returnCode) {
|
||||||
|
std::cerr << "Error " << errno << " on unlockpt()\n";
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
int slave = open(ptsname(master), O_RDWR);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
// Create the child process
|
||||||
|
if (fork())
|
||||||
|
{
|
||||||
|
|
||||||
|
// FATHER
|
||||||
|
|
||||||
|
// Close the slave side of the PTY
|
||||||
|
close(slave);
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
struct termios slave_orig_term_settings; // Saved terminal settings
|
||||||
|
struct termios new_term_settings; // Current terminal settings
|
||||||
|
|
||||||
|
// CHILD
|
||||||
|
|
||||||
|
// Close the master side of the PTY
|
||||||
|
close(master);
|
||||||
|
|
||||||
|
// Save the defaults parameters of the slave side of the PTY
|
||||||
|
returnCode = tcgetattr(slave, &slave_orig_term_settings);
|
||||||
|
|
||||||
|
// Set RAW mode on slave side of PTY
|
||||||
|
new_term_settings = slave_orig_term_settings;
|
||||||
|
cfmakeraw (&new_term_settings);
|
||||||
|
tcsetattr (slave, TCSANOW, &new_term_settings);
|
||||||
|
|
||||||
|
// The slave side of the PTY becomes the standard input and outputs of the child process
|
||||||
|
close(0); // Close standard input (current terminal)
|
||||||
|
close(1); // Close standard output (current terminal)
|
||||||
|
close(2); // Close standard error (current terminal)
|
||||||
|
|
||||||
|
dup(slave); // PTY becomes standard input (0)
|
||||||
|
dup(slave); // PTY becomes standard output (1)
|
||||||
|
dup(slave); // PTY becomes standard error (2)
|
||||||
|
|
||||||
|
// Now the original file descriptor is useless
|
||||||
|
close(slave);
|
||||||
|
|
||||||
|
// Make the current process a new session leader
|
||||||
|
setsid();
|
||||||
|
|
||||||
|
// As the child is a session leader, set the controlling terminal to be the slave side of the PTY
|
||||||
|
// (Mandatory for programs like the shell to make them manage correctly their outputs)
|
||||||
|
ioctl(0, TIOCSCTTY, 1);
|
||||||
|
|
||||||
|
// Execution of the program
|
||||||
|
{
|
||||||
|
char* const* args = nullptr;
|
||||||
|
returnCode = execvp("bash", args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if Error...
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
}
|
||||||
|
|
||||||
|
void Terminal::run() {
|
||||||
|
|
||||||
|
static char input[150];
|
||||||
|
static char output[150];
|
||||||
|
static int returnCode;
|
||||||
|
static timeval timeout; timeout = { 0, 0 };
|
||||||
|
fd_set fd_in;
|
||||||
|
// Wait for data from standard input and master side of PTY
|
||||||
|
FD_ZERO(&fd_in);
|
||||||
|
FD_SET(master, &fd_in);
|
||||||
|
|
||||||
|
returnCode = select(master + 1, &fd_in, NULL, NULL, &timeout);
|
||||||
|
switch(returnCode) {
|
||||||
|
case -1: fprintf(stderr, "Error %d on select()\n", errno);
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
default: {
|
||||||
|
// If data on master side of PTY
|
||||||
|
if (FD_ISSET(master, &fd_in)) {
|
||||||
|
returnCode = read(master, output, sizeof(output));
|
||||||
|
if (returnCode > 0) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (returnCode < 0) {
|
||||||
|
fprintf(stderr, "Error %d on read master PTY\n", errno);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // End switch
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::Begin("Terminal Module");
|
||||||
|
|
||||||
|
ImGui::Text("%s", output);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::InputText("", input, 150);
|
||||||
|
|
||||||
|
if(ImGui::Button("send"))
|
||||||
|
write(master, input, returnCode);
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
20
modules/Terminal/src/Terminal.h
Normal file
20
modules/Terminal/src/Terminal.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#include "Archimedes.h"
|
||||||
|
|
||||||
|
class Terminal : public Archimedes::Module {
|
||||||
|
|
||||||
|
public:
|
||||||
|
Terminal(Archimedes::App*, void*);
|
||||||
|
|
||||||
|
~Terminal();
|
||||||
|
|
||||||
|
void onLoad();
|
||||||
|
|
||||||
|
void run();
|
||||||
|
private:
|
||||||
|
int master;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef MAINGUI_DYNAMIC
|
||||||
|
#define MODULE_TYPE Terminal
|
||||||
|
#include "endModule.h"
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user