Add a Unix pty<->pconsole adapter.
This commit is contained in:
parent
1aaf102905
commit
19d9c1832c
2
Makefile
2
Makefile
@ -1,7 +1,9 @@
|
||||
all :
|
||||
cd agent && $(MAKE)
|
||||
cd libpconsole && $(MAKE)
|
||||
cd unix-adapter && $(MAKE)
|
||||
|
||||
clean :
|
||||
cd agent && $(MAKE) clean
|
||||
cd libpconsole && $(MAKE) clean
|
||||
cd unix-adapter && $(MAKE) clean
|
||||
|
18
unix-adapter/Makefile
Normal file
18
unix-adapter/Makefile
Normal file
@ -0,0 +1,18 @@
|
||||
include ../config.mk
|
||||
|
||||
PROGRAM = pconsole
|
||||
OBJECTS = main.o
|
||||
CXXFLAGS += -I../include
|
||||
LDFLAGS += ../libpconsole/pconsole.dll
|
||||
|
||||
all : $(PROGRAM)
|
||||
|
||||
$(PROGRAM) : $(OBJECTS)
|
||||
@echo Linking $@
|
||||
@$(CXX) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
.PHONY : clean
|
||||
clean:
|
||||
rm -f $(PROGRAM) *.o *.d
|
||||
|
||||
-include $(OBJECTS:.o=.d)
|
196
unix-adapter/main.cc
Normal file
196
unix-adapter/main.cc
Normal file
@ -0,0 +1,196 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <pconsole.h>
|
||||
|
||||
static int signalWriteFd;
|
||||
|
||||
|
||||
// Put the input terminal into non-blocking non-canonical mode.
|
||||
static termios setRawTerminalMode()
|
||||
{
|
||||
if (!isatty(STDIN_FILENO)) {
|
||||
fprintf(stderr, "input is not a tty\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!isatty(STDOUT_FILENO)) {
|
||||
fprintf(stderr, "output is not a tty\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// This code makes the terminal output non-blocking.
|
||||
int flags = fcntl(STDOUT_FILENO, F_GETFL, 0);
|
||||
if (flags == -1) {
|
||||
perror("fcntl F_GETFL on stdout failed");
|
||||
exit(1);
|
||||
}
|
||||
if (fcntl(STDOUT_FILENO, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||
perror("fcntl F_SETFL on stdout failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
termios buf;
|
||||
if (tcgetattr(STDIN_FILENO, &buf) < 0) {
|
||||
perror("tcgetattr failed");
|
||||
exit(1);
|
||||
}
|
||||
termios saved = buf;
|
||||
buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
|
||||
buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
||||
buf.c_cflag &= ~(CSIZE | PARENB);
|
||||
buf.c_cflag |= CS8;
|
||||
buf.c_oflag &= ~OPOST;
|
||||
buf.c_cc[VMIN] = 0;
|
||||
buf.c_cc[VTIME] = 0;
|
||||
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &buf) < 0) {
|
||||
fprintf(stderr, "tcsetattr failed\n");
|
||||
exit(1);
|
||||
}
|
||||
return saved;
|
||||
}
|
||||
|
||||
static void restoreTerminalMode(termios original)
|
||||
{
|
||||
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &original) < 0) {
|
||||
perror("error restoring terminal mode");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void terminalResized(int signo)
|
||||
{
|
||||
char dummy = 0;
|
||||
write(signalWriteFd, &dummy, 1);
|
||||
}
|
||||
|
||||
static void pconsoleIo(pconsole_t *pconsole)
|
||||
{
|
||||
char dummy = 0;
|
||||
write(signalWriteFd, &dummy, 1);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
winsize sz;
|
||||
ioctl(STDIN_FILENO, TIOCGWINSZ, &sz);
|
||||
|
||||
pconsole_t *pconsole = pconsole_open(sz.ws_col, sz.ws_row);
|
||||
if (pconsole == NULL) {
|
||||
fprintf(stderr, "Error creating pconsole.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pconsole_set_io_cb(pconsole, pconsoleIo);
|
||||
|
||||
{
|
||||
struct sigaction resizeSigAct;
|
||||
memset(&resizeSigAct, 0, sizeof(resizeSigAct));
|
||||
resizeSigAct.sa_handler = terminalResized;
|
||||
resizeSigAct.sa_flags = SA_RESTART;
|
||||
sigaction(SIGWINCH, &resizeSigAct, NULL);
|
||||
}
|
||||
|
||||
termios mode = setRawTerminalMode();
|
||||
int signalReadFd;
|
||||
|
||||
const int bufSize = 4096;
|
||||
char writeBuf[bufSize];
|
||||
int writeBufAmount;
|
||||
char buf[bufSize];
|
||||
int amount;
|
||||
|
||||
{
|
||||
int pipeFd[2];
|
||||
if (pipe2(pipeFd, O_NONBLOCK) != 0) {
|
||||
perror("Could not create pipe");
|
||||
exit(1);
|
||||
}
|
||||
signalReadFd = pipeFd[0];
|
||||
signalWriteFd = pipeFd[1];
|
||||
}
|
||||
|
||||
while (true) {
|
||||
fd_set readfds;
|
||||
fd_set writefds;
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&writefds);
|
||||
FD_SET(signalReadFd, &readfds);
|
||||
if (pconsole_get_output_queue_size(pconsole) < bufSize)
|
||||
FD_SET(STDIN_FILENO, &readfds);
|
||||
if (writeBufAmount > 0)
|
||||
FD_SET(STDOUT_FILENO, &writefds);
|
||||
|
||||
if (select(signalReadFd + 1, &readfds, &writefds, NULL, NULL) < 0) {
|
||||
perror("select failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Check for terminal resize.
|
||||
{
|
||||
winsize sz2;
|
||||
ioctl(STDIN_FILENO, TIOCGWINSZ, &sz2);
|
||||
if (memcmp(&sz, &sz2, sizeof(sz)) != 0) {
|
||||
sz = sz2;
|
||||
pconsole_set_size(pconsole, sz.ws_col, sz.ws_row);
|
||||
}
|
||||
}
|
||||
|
||||
// Discard any data in the signal pipe.
|
||||
amount = read(signalReadFd, buf, bufSize);
|
||||
if (amount == 0 || amount < 0 && errno != EAGAIN) {
|
||||
perror("error reading internal signal fd");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Read from the pty and write to the pconsole.
|
||||
amount = bufSize - pconsole_get_output_queue_size(pconsole);
|
||||
if (amount > 0) {
|
||||
amount = read(STDIN_FILENO, buf, amount);
|
||||
if (amount == 0) {
|
||||
break;
|
||||
} else if (amount < 0 && errno != EAGAIN) {
|
||||
perror("error reading from pty");
|
||||
exit(1);
|
||||
} else if (amount > 0) {
|
||||
pconsole_write(pconsole, buf, amount);
|
||||
}
|
||||
}
|
||||
|
||||
// Read from the pconsole.
|
||||
amount = bufSize - writeBufAmount;
|
||||
if (amount > 0) {
|
||||
amount = pconsole_read(pconsole, buf + writeBufAmount, amount);
|
||||
if (amount == 0)
|
||||
break;
|
||||
else if (amount > 0)
|
||||
writeBufAmount += amount;
|
||||
}
|
||||
|
||||
// Write to the pty.
|
||||
if (writeBufAmount > 0) {
|
||||
amount = write(STDOUT_FILENO, writeBuf, writeBufAmount);
|
||||
if (amount == 0) {
|
||||
break;
|
||||
} else if (amount < 0 && errno != EAGAIN) {
|
||||
perror("error writing to pty");
|
||||
} else if (amount > 0) {
|
||||
int remaining = writeBufAmount - amount;
|
||||
if (amount < writeBufAmount)
|
||||
memmove(writeBuf, writeBuf + amount, remaining);
|
||||
writeBufAmount = remaining;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Get the pconsole child exit code and exit with it.
|
||||
|
||||
restoreTerminalMode(mode);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user