QgsGrassShell::QgsGrassShell( QgsGrassTools *tools, QTabWidget *parent, const char *name ) : QFrame( parent ), mTools( tools ), mTabWidget( parent ) { Q_UNUSED( name ); QVBoxLayout *mainLayout = new QVBoxLayout( this ); QTermWidget *mTerminal = new QTermWidget( 0, this ); initTerminal( mTerminal ); QShortcut *pasteShortcut = new QShortcut( QKeySequence( tr( "Ctrl+Shift+V" ) ), mTerminal ); QShortcut *copyShortcut = new QShortcut( QKeySequence( tr( "Ctrl+Shift+C" ) ), mTerminal ); mainLayout->addWidget( mTerminal ); setLayout( mainLayout ); connect( mTerminal, SIGNAL( finished() ), this, SLOT( closeShell() ) ); connect( pasteShortcut, SIGNAL( activated() ), mTerminal, SLOT( pasteClipboard() ) ); connect( copyShortcut, SIGNAL( activated() ), mTerminal, SLOT( copyClipboard() ) ); // TODO: find a better way to manage the lockfile. // Locking should not be done here, a mapset is either locked by GRASS if QGIS is started from GRASS or it is created by QgsGrass::openMapset /* mLockFilename = QgsGrass::lockFilePath(); QFile::remove( mLockFilename + ".qgis" ); if ( !QFile::rename( mLockFilename, mLockFilename + ".qgis" ) ) { QMessageBox::warning( this, tr( "Warning" ), tr( "Cannot rename the lock file %1" ).arg( mLockFilename ) ); } */ mTerminal->setSize( 80, 25 ); mTerminal->setColorScheme( COLOR_SCHEME_BLACK_ON_LIGHT_YELLOW ); mTerminal->startShellProgram(); mTerminal->setFocus( Qt::MouseFocusReason ); }
SSH::~SSH() { if (_bShellOpen) { closeShell(); } if (_bChanOpen) { closeChannel(); } _logger->debug("Destructing SSH instance"); if (_connected) ssh_disconnect(_ssh); if (_ssh != NULL) { _logger->trace("Freeing SSH object"); ssh_free(_ssh); } _logger->debug("SSH instance destructed"); }
QgsGrassShell::QgsGrassShell( QgsGrassTools *tools, QTabWidget * parent, const char * name ): QDialog( parent ), QgsGrassShellBase(), mTools( tools ) { mValid = false; mSkipLines = 2; mTabWidget = parent; #ifdef WIN32 QMessageBox::warning( 0, "Warning", "GRASS Shell is not supported on Windows." ); return; #else setupUi( this ); QGridLayout *layout = new QGridLayout( mTextFrame, 1, 1 ); mText = new QgsGrassShellText( this, mTextFrame ); layout->addWidget( mText, 0, 0 ); mText->show(); connect( mCloseButton, SIGNAL( clicked() ), this, SLOT( closeShell() ) ); mFont = QFont( "Courier", 10 ); mAppDir = mTools->appDir(); #ifndef Q_WS_MAC // Qt4.3.2/Mac Q3TextEdit readOnly property causes keys to be processed as keyboard actions mText->setReadOnly( TRUE ); #endif //mText->setFocusPolicy ( QWidget::NoFocus ); // To get key press directly #ifndef HAVE_OPENPTY mText->append( "GRASS shell is not supported" ); return; #endif // TODO set cursor IbeamCursor // This does not work - the cursor is used for scrollbars -> disabled //mText->setCursor ( QCursor(Qt::IbeamCursor) ); mParagraph = -1; // first will be 0 mIndex = -1; mNewLine = true; for ( int i = 0; i < ModeCount; i++ ) { resetMode( i ); } int uid; seteuid( uid = getuid() ); /* Run unprivileged */ // Get and open pseudo terminal // Note: 0 (stdin), 1 (stdout) or 2 (stderr) int fdSlave; // slave file descriptor seteuid( 0 ); int ret = openpty( &mFdMaster, &fdSlave, NULL, NULL, NULL ); if ( ret != 0 ) { QMessageBox::warning( 0, "Warning", "Cannot open pseudo terminal" ); return; } fchown( fdSlave, uid, ( gid_t ) - 1 ); fchmod( fdSlave, S_IRUSR | S_IWUSR ); seteuid( uid ); QgsDebugMsg( QString( "mFdMaster = %1" ).arg( mFdMaster ) ); QgsDebugMsg( QString( "fdSlave = %1" ).arg( fdSlave ) ); fcntl( mFdMaster, F_SETFL, O_NDELAY ); //fcntl( fdSlave, F_SETFL, O_NDELAY); // enable? QString slaveName = ttyname( fdSlave ); QgsDebugMsg( QString( "master ttyname = %1" ).arg( ttyname( mFdMaster ) ) ); QgsDebugMsg( QString( "slave ttyname = %1" ).arg( ttyname( fdSlave ) ) ); //::close( fdSlave ); // -> crash // Fork slave and open shell int pid = fork(); QgsDebugMsg( QString( "pid = %1" ).arg( pid ) ); if ( pid == -1 ) { QMessageBox::warning( 0, "Warning", "Cannot fork shell" ); return; } // Child - slave if ( pid == 0 ) { QgsDebugMsg( "child ->" ); // TODO close all opened file descriptors - close(0)??? ::close( mFdMaster ); //::close( fdSlave ); // -> freeze setsid(); seteuid( 0 ); int fd = ::open(( char* ) slaveName.ascii(), O_RDWR ); if ( fd < 0 ) { QMessageBox::warning( 0, "Warning", "Cannot open slave file " "in child process" ); return; } fchown( fd, uid, ( gid_t ) - 1 ); fchmod( fd, S_IRUSR | S_IWUSR ); setuid( uid ); dup2( fd, 0 ); /* stdin */ dup2( fd, 1 ); /* stdout */ dup2( fd, 2 ); /* stderr */ // TODO: test if shell is available QString shell = ( getenv( "SHELL" ) ); if ( shell.isEmpty() ) { shell = "/bin/bash"; } const char *norc = ""; QFileInfo si( shell ); if ( si.fileName() == "bash" || si.fileName() == "sh" ) { norc = "--norc"; } else if ( si.fileName() == "tcsh" || si.fileName() == "csh" ) { norc = "-f"; } // Warning: execle + --norc will not inherit not given variables // -> overwrite here const char *env = "GRASS_MESSAGE_FORMAT=gui"; char *envstr = new char[strlen( env )+1]; strcpy( envstr, env ); putenv( envstr ); putenv(( char * ) "GISRC_MODE_MEMORY" ); // unset env = "PS1=GRASS > "; envstr = new char[strlen( env )+1]; strcpy( envstr, env ); putenv( envstr ); env = "TERM=vt100"; envstr = new char[strlen( env )+1]; strcpy( envstr, env ); putenv( envstr ); //char *envar[] = { "PS1=GRASS > ", "TERM=vt100", "GISRC_MODE_MEMORY=", // "GRASS_MESSAGE_FORMAT=gui", (char *)0 }; //execle ( (char*)shell.ascii(), (char *)si.fileName().ascii(), // norc, (char *) 0, envar); execl(( char* )shell.ascii(), ( char * )si.fileName().ascii(), norc, ( char * ) 0 ); // Failed (QMessageBox here does not work) fprintf( stderr, "GRASS_INFO_ERROR(1,1): Cannot start shell %s\n", ( char* )shell.ascii() ); exit( 1 ); } mPid = pid; // Create socket notifier mOutNotifier = new QSocketNotifier( mFdMaster, QSocketNotifier::Read, this ); QObject::connect( mOutNotifier, SIGNAL( activated( int ) ), this, SLOT( readStdout( int ) ) ); // Set tab stops ??? mTabStop.resize( 200 ); for ( int i = 0 ; i * 8 < ( int )mTabStop.size(); i++ ) { mTabStop[i*8] = true; } // Set trap to write history on SIGUSR1 //QString trap = "trap 'history -w' SIGUSR1\015\012"; QString trap = "trap 'history -w' SIGUSR1\015"; write( mFdMaster, trap.ascii(), trap.length() ); mText->clear(); resizeTerminal(); mValid = true; #endif // !WIN32 }