#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(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) ); //qDebug() << " - PTY:" << this->portName(); return this->open(QIODevice::ReadWrite); //return true; } } // === 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 // Example my_args which works // char *my_args[] = { "/bin/csh", NULL }; //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; }