Esempio n. 1
0
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 );
}
Esempio n. 2
0
 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
}