#include "TtyProcess.h" //Standard C library functions for PTY access/setup #include #include #include #include #include #include #include TTYProcess::TTYProcess(QObject *parent) : QFile(parent){ childProc = 0; } TTYProcess::~TTYProcess(){ kill(childProc, SIGKILL); } // === PUBLIC === bool TTYProcess::startTTY(int &retfd, QString prog, QStringList args){ //Turn the program/arguments into C-compatible arrays char cprog[prog.length()]; strcpy(cprog, prog.toLocal8Bit().data()); char *cargs[args.length()+2]; QByteArray nullarray; for(int i=0; isetFileName( ptsname(FD) ); retfd = FD; ttyfd = FD; qDebug() << " - PTY:" << ptsname(FD); return this->open(QIODevice::ReadWrite | QIODevice::Unbuffered); //return true; } } void TTYProcess::writeTTY(QByteArray output){ int written = ::write(ttyfd, output.data(), output.size()); qDebug() << "Wrote:" << written; } // === PRIVATE === pid_t TTYProcess::LaunchProcess(int& fd, char *prog, char **child_args){ //Returns: -1 for errors, positive value (file descriptor) for the master side of the TTY to watch //First open/setup a new pseudo-terminal file/device on the system (master side) fd = posix_openpt(O_RDWR); //open read/write if(fd<0){ return -1; } //could not create pseudo-terminal int rc = grantpt(fd); //set permissions if(rc!=0){ return -1; } rc = unlockpt(fd); //unlock file (ready for use) if(rc!=0){ return -1; } //Now fork, return the Master device and setup the child pid_t PID = fork(); if(PID==0){ //SLAVE/child int fds = ::open(ptsname(fd), O_RDWR); //open slave side read/write ::close(fd); //close the master side from the slave thread //Adjust the slave side mode to RAW struct termios TSET; rc = tcgetattr(fds, &TSET); //read the current settings cfmakeraw(&TSET); //set the RAW mode on the settings tcsetattr(fds, TCSANOW, &TSET); //apply the changed settings //Change the controlling terminal in child thread to the slave PTY ::close(0); //close current terminal standard input ::close(1); //close current terminal standard output ::close(2); //close current terminal standard error dup(fds); // Set slave PTY as standard input (0); dup(fds); // Set slave PTY as standard output (1); dup(fds); // Set slave PTY as standard error (2); setsid(); //Make current process new session leader (so we can set controlling terminal) ioctl(0,TIOCSCTTY, 1); //Set the controlling terminal to the slave PTY //Execute the designated program rc = execvp(prog, child_args); ::close(fds); //no need to keep original file descriptor open any more exit(rc); } //MASTER thread (or error) return PID; }