Diffstat (limited to 'core/launcher/qprocess_unix.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | core/launcher/qprocess_unix.cpp | 93 |
1 files changed, 46 insertions, 47 deletions
diff --git a/core/launcher/qprocess_unix.cpp b/core/launcher/qprocess_unix.cpp index 19a8c93..d62e4e6 100644 --- a/core/launcher/qprocess_unix.cpp +++ b/core/launcher/qprocess_unix.cpp @@ -9,60 +9,59 @@ ** packaging of this file. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ** See http://www.trolltech.com/gpl/ for GPL licensing information. ** ** Contact info@trolltech.com if any conditions of this licensing are ** not clear to you. ** **********************************************************************/ -//#include "qplatformdefs.h" - // Solaris redefines connect -> __xnet_connect with _XOPEN_SOURCE_EXTENDED. #if defined(connect) #undef connect #endif #include "qprocess.h" -#ifndef QT_NO_PROCESS +/* OPIE */ +#include <opie2/odebug.h> +using namespace Opie::Core; -#include "qapplication.h" -#include "qqueue.h" -#include "qlist.h" -#include "qsocketnotifier.h" -#include "qtimer.h" -#include "qregexp.h" +/* QT */ +#ifndef QT_NO_PROCESS +#include <qapplication.h> +#include <qqueue.h> +#include <qlist.h> +#include <qsocketnotifier.h> +#include <qtimer.h> +#include <qregexp.h> #include "qcleanuphandler_p.h" +/* STD */ #include <stdlib.h> - -// ### FOR Qt 2.3 compat #include <unistd.h> #include <signal.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/wait.h> #include <sys/fcntl.h> - +#include <sys/resource.h> #include <errno.h> - #ifdef Q_OS_MACX #include <sys/time.h> #endif -#include <sys/resource.h> #ifdef __MIPSEL__ # ifndef SOCK_DGRAM # define SOCK_DGRAM 1 # endif # ifndef SOCK_STREAM # define SOCK_STREAM 2 # endif #endif //#define QT_QPROCESS_DEBUG @@ -123,34 +122,34 @@ public: child processes: if the process is finished, the QProcess class may still be there; furthermore a user can use QProcess to start more than one process. The helper-class QProc has the semantics that one instance of this class maps directly to a running child process. */ class QProc { public: QProc( pid_t p, QProcess *proc=0 ) : pid(p), process(proc) { #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProc: Constructor for pid %d and QProcess %p", pid, process ); + odebug << "QProc: Constructor for pid " << pid << " and QProcess " << process << "" << oendl; #endif socketStdin = 0; socketStdout = 0; socketStderr = 0; } ~QProc() { #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProc: Destructor for pid %d and QProcess %p", pid, process ); + odebug << "QProc: Destructor for pid " << pid << " and QProcess " << process << "" << oendl; #endif if ( process != 0 ) { if ( process->d->notifierStdin ) process->d->notifierStdin->setEnabled( FALSE ); if ( process->d->notifierStdout ) process->d->notifierStdout->setEnabled( FALSE ); if ( process->d->notifierStderr ) process->d->notifierStderr->setEnabled( FALSE ); process->d->proc = 0; } if( socketStdin != 0 ) ::close( socketStdin ); @@ -204,102 +203,102 @@ QProcessManager::QProcessManager() { procList = new QList<QProc>; procList->setAutoDelete( TRUE ); // The SIGCHLD handler writes to a socket to tell the manager that // something happened. This is done to get the processing in sync with the // event reporting. if ( ::socketpair( AF_UNIX, SOCK_STREAM, 0, sigchldFd ) ) { sigchldFd[0] = 0; sigchldFd[1] = 0; } else { #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcessManager: install socket notifier (%d)", sigchldFd[1] ); + odebug << "QProcessManager: install socket notifier (" << sigchldFd[1] << ")" << oendl; #endif QSocketNotifier *sn = new QSocketNotifier( sigchldFd[1], QSocketNotifier::Read, this ); connect( sn, SIGNAL(activated(int)), this, SLOT(sigchldHnd(int)) ); sn->setEnabled( TRUE ); } // install a SIGCHLD handler and ignore SIGPIPE struct sigaction act; #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcessManager: install a SIGCHLD handler" ); + odebug << "QProcessManager: install a SIGCHLD handler" << oendl; #endif act.sa_handler = qt_C_sigchldHnd; sigemptyset( &(act.sa_mask) ); sigaddset( &(act.sa_mask), SIGCHLD ); act.sa_flags = SA_NOCLDSTOP; #if defined(SA_RESTART) act.sa_flags |= SA_RESTART; #endif if ( sigaction( SIGCHLD, &act, &oldactChld ) != 0 ) - qWarning( "Error installing SIGCHLD handler" ); + owarn << "Error installing SIGCHLD handler" << oendl; #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcessManager: install a SIGPIPE handler (SIG_IGN)" ); + odebug << "QProcessManager: install a SIGPIPE handler (SIG_IGN)" << oendl; #endif /* Using qt_C_sigpipeHnd rather than SIG_IGN is a workaround for a strange problem where GNU tar (called by backuprestore) would hang on filesystem-full. Strangely, the qt_C_sigpipeHnd is never even called, yet this avoids the hang. */ act.sa_handler = qt_C_sigpipeHnd; sigemptyset( &(act.sa_mask) ); sigaddset( &(act.sa_mask), SIGPIPE ); act.sa_flags = 0; if ( sigaction( SIGPIPE, &act, &oldactPipe ) != 0 ) - qWarning( "Error installing SIGPIPE handler" ); + owarn << "Error installing SIGPIPE handler" << oendl; } QProcessManager::~QProcessManager() { delete procList; if ( sigchldFd[0] != 0 ) ::close( sigchldFd[0] ); if ( sigchldFd[1] != 0 ) ::close( sigchldFd[1] ); // restore SIGCHLD handler #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcessManager: restore old sigchild handler" ); + odebug << "QProcessManager: restore old sigchild handler" << oendl; #endif if ( sigaction( SIGCHLD, &oldactChld, 0 ) != 0 ) - qWarning( "Error restoring SIGCHLD handler" ); + owarn << "Error restoring SIGCHLD handler" << oendl; #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcessManager: restore old sigpipe handler" ); + odebug << "QProcessManager: restore old sigpipe handler" << oendl; #endif if ( sigaction( SIGPIPE, &oldactPipe, 0 ) != 0 ) - qWarning( "Error restoring SIGPIPE handler" ); + owarn << "Error restoring SIGPIPE handler" << oendl; } void QProcessManager::append( QProc *p ) { procList->append( p ); #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcessManager: append process (procList.count(): %d)", procList->count() ); + odebug << "QProcessManager: append process (procList.count(): " << procList->count() << ")" << oendl; #endif } void QProcessManager::remove( QProc *p ) { procList->remove( p ); #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcessManager: remove process (procList.count(): %d)", procList->count() ); + odebug << "QProcessManager: remove process (procList.count(): " << procList->count() << ")" << oendl; #endif cleanup(); } void QProcessManager::cleanup() { if ( procList->count() == 0 ) { QTimer::singleShot( 0, this, SLOT(removeMe()) ); } } void QProcessManager::removeMe() @@ -307,65 +306,65 @@ void QProcessManager::removeMe() if ( procList->count() == 0 ) { qprocess_cleanup_procmanager.remove( &QProcessPrivate::procManager ); QProcessPrivate::procManager = 0; delete this; } } void QProcessManager::sigchldHnd( int fd ) { char tmp; ::read( fd, &tmp, sizeof(tmp) ); #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcessManager::sigchldHnd()" ); + odebug << "QProcessManager::sigchldHnd()" << oendl; #endif QProc *proc; QProcess *process; bool removeProc; proc = procList->first(); while ( proc != 0 ) { removeProc = FALSE; process = proc->process; QProcess *process_exit_notify=0; if ( process != 0 ) { if ( !process->isRunning() ) { #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcessManager::sigchldHnd() (PID: %d): process exited (QProcess available)", proc->pid ); + odebug << "QProcessManager::sigchldHnd() (PID: " << proc->pid << "): process exited (QProcess available)" << oendl; #endif // read pending data int nbytes = 0; if ( ::ioctl(proc->socketStdout, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) { #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcessManager::sigchldHnd() (PID: %d): reading %d bytes of pending data on stdout", proc->pid, nbytes ); + odebug << "QProcessManager::sigchldHnd() (PID: " << proc->pid << "): reading " << nbytes << " bytes of pending data on stdout" << oendl; #endif process->socketRead( proc->socketStdout ); } nbytes = 0; if ( ::ioctl(proc->socketStderr, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) { #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcessManager::sigchldHnd() (PID: %d): reading %d bytes of pending data on stderr", proc->pid, nbytes ); + odebug << "QProcessManager::sigchldHnd() (PID: " << proc->pid << "): reading " << nbytes << " bytes of pending data on stderr" << oendl; #endif process->socketRead( proc->socketStderr ); } if ( process->notifyOnExit ) process_exit_notify = process; removeProc = TRUE; } } else { int status; if ( ::waitpid( proc->pid, &status, WNOHANG ) == proc->pid ) { #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcessManager::sigchldHnd() (PID: %d): process exited (QProcess not available)", proc->pid ); + odebug << "QProcessManager::sigchldHnd() (PID: " << proc->pid << "): process exited (QProcess not available)" << oendl; #endif removeProc = TRUE; } } if ( removeProc ) { QProc *oldproc = proc; proc = procList->next(); remove( oldproc ); } else { proc = procList->next(); } if ( process_exit_notify ) @@ -377,42 +376,42 @@ void QProcessManager::sigchldHnd( int fd ) /*********************************************************************** * * QProcessPrivate * **********************************************************************/ QProcessManager *QProcessPrivate::procManager = 0; QProcessPrivate::QProcessPrivate() { #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcessPrivate: Constructor" ); + odebug << "QProcessPrivate: Constructor" << oendl; #endif stdinBufRead = 0; notifierStdin = 0; notifierStdout = 0; notifierStderr = 0; exitValuesCalculated = FALSE; socketReadCalled = FALSE; proc = 0; } QProcessPrivate::~QProcessPrivate() { #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcessPrivate: Destructor" ); + odebug << "QProcessPrivate: Destructor" << oendl; #endif if ( proc != 0 ) { if ( proc->socketStdin != 0 ) { ::close( proc->socketStdin ); proc->socketStdin = 0; } proc->process = 0; } while ( !stdinBuf.isEmpty() ) { delete stdinBuf.dequeue(); @@ -590,25 +589,25 @@ QProcess::~QProcess() You can call this function even when there already is a running process in this object. In this case, QProcess closes standard input of the old process and deletes pending data, i.e., you loose all control over that process, but the process is not terminated. This applies also if the process could not be started. (On operating systems that have zombie processes, Qt will also wait() on the old process.) \sa launch() closeStdin() */ bool QProcess::start( QStringList *env ) { #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcess::start()" ); + odebug << "QProcess::start()" << oendl; #endif reset(); int sStdin[2]; int sStdout[2]; int sStderr[2]; // open sockets for piping if ( (comms & Stdin) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdin ) == -1 ) { return FALSE; } if ( (comms & Stderr) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStderr ) == -1 ) { @@ -626,25 +625,25 @@ bool QProcess::start( QStringList *env ) fd[0] = 0; fd[1] = 0; } // construct the arguments for exec QCString *arglistQ = new QCString[ _arguments.count() + 1 ]; const char** arglist = new const char*[ _arguments.count() + 1 ]; int i = 0; for ( QStringList::Iterator it = _arguments.begin(); it != _arguments.end(); ++it ) { arglistQ[i] = (*it).local8Bit(); arglist[i] = arglistQ[i]; #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcess::start(): arg %d = %s", i, arglist[i] ); + odebug << "QProcess::start(): arg " << i << " = " << arglist[i] << "" << oendl; #endif i++; } arglist[i] = 0; // Must make sure signal handlers are installed before exec'ing // in case the process exits quickly. if ( d->procManager == 0 ) { d->procManager = new QProcessManager; qprocess_cleanup_procmanager.add( &d->procManager ); } @@ -790,25 +789,25 @@ bool QProcess::start( QStringList *env ) this, SLOT(socketRead(int)) ); if ( ioRedirection ) d->notifierStderr->setEnabled( TRUE ); } // cleanup and return delete[] arglistQ; delete[] arglist; return TRUE; error: #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcess::start(): error starting process" ); + odebug << "QProcess::start(): error starting process" << oendl; #endif if ( d->procManager ) d->procManager->cleanup(); if ( comms & Stdin ) { ::close( sStdin[1] ); ::close( sStdin[0] ); } if ( comms & Stdout ) { ::close( sStdout[0] ); ::close( sStdout[1] ); } if ( comms & Stderr ) { @@ -869,67 +868,67 @@ void QProcess::kill() const ::kill( d->proc->pid, SIGKILL ); } /*! Returns TRUE if the process is running, otherwise FALSE. \sa normalExit() exitStatus() processExited() */ bool QProcess::isRunning() const { if ( d->exitValuesCalculated ) { #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcess::isRunning(): FALSE (already computed)" ); + odebug << "QProcess::isRunning(): FALSE (already computed)" << oendl; #endif return FALSE; } if ( d->proc == 0 ) return FALSE; int status; if ( ::waitpid( d->proc->pid, &status, WNOHANG ) == d->proc->pid ) { // compute the exit values QProcess *that = (QProcess*)this; // mutable that->exitNormal = WIFEXITED( status ) != 0; if ( exitNormal ) { that->exitStat = (char)WEXITSTATUS( status ); } d->exitValuesCalculated = TRUE; #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcess::isRunning() (PID: %d): FALSE", d->proc->pid ); + odebug << "QProcess::isRunning() (PID: " << d->proc->pid << "): FALSE" << oendl; #endif return FALSE; } #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcess::isRunning() (PID: %d): TRUE", d->proc->pid ); + odebug << "QProcess::isRunning() (PID: " << d->proc->pid << "): TRUE" << oendl; #endif return TRUE; } /*! Writes the data \a buf to the standard input of the process. The process may or may not read this data. This function returns immediately; the QProcess class might write the data at a later point (you have to enter the event loop for that). When all the data is written to the process, the signal wroteToStdin() is emitted. This does not mean that the process really read the data, since this class only detects when it was able to write the data to the operating system. \sa wroteToStdin() closeStdin() readStdout() readStderr() */ void QProcess::writeToStdin( const QByteArray& buf ) { #if defined(QT_QPROCESS_DEBUG) -// qDebug( "QProcess::writeToStdin(): write to stdin (%d)", d->socketStdin ); +// odebug << "QProcess::writeToStdin(): write to stdin (" << d->socketStdin << ")" << oendl; #endif d->stdinBuf.enqueue( new QByteArray(buf) ); if ( d->notifierStdin != 0 ) d->notifierStdin->setEnabled( TRUE ); } /*! Closes standard input of the process. This function also deletes pending data that is not written to standard input yet. @@ -938,48 +937,48 @@ void QProcess::writeToStdin( const QByteArray& buf ) */ void QProcess::closeStdin() { if ( d->proc == 0 ) return; if ( d->proc->socketStdin !=0 ) { while ( !d->stdinBuf.isEmpty() ) { delete d->stdinBuf.dequeue(); } delete d->notifierStdin; d->notifierStdin = 0; if ( ::close( d->proc->socketStdin ) != 0 ) { - qWarning( "Could not close stdin of child process" ); + owarn << "Could not close stdin of child process" << oendl; } #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcess::closeStdin(): stdin (%d) closed", d->proc->socketStdin ); + odebug << "QProcess::closeStdin(): stdin (" << d->proc->socketStdin << ") closed" << oendl; #endif d->proc->socketStdin = 0; } } /* This private slot is called when the process has outputted data to either standard output or standard error. */ void QProcess::socketRead( int fd ) { if ( d->socketReadCalled ) { // the slots that are connected to the readyRead...() signals might // trigger a recursive call of socketRead(). Avoid this since you get a // blocking read otherwise. return; } #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcess::socketRead(): %d", fd ); + odebug << "QProcess::socketRead(): " << fd << "" << oendl; #endif if ( fd == 0 ) return; const int bufsize = 4096; QByteArray *buffer = 0; uint oldSize; int n; if ( fd == d->proc->socketStdout ) { buffer = &d->bufStdout; } else if ( fd == d->proc->socketStderr ) { buffer = &d->bufStderr; } else { @@ -990,35 +989,35 @@ void QProcess::socketRead( int fd ) // read data oldSize = buffer->size(); buffer->resize( oldSize + bufsize ); n = ::read( fd, buffer->data()+oldSize, bufsize ); if ( n > 0 ) buffer->resize( oldSize + n ); else buffer->resize( oldSize ); // eof or error? if ( n == 0 || n == -1 ) { if ( fd == d->proc->socketStdout ) { #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcess::socketRead(): stdout (%d) closed", fd ); + odebug << "QProcess::socketRead(): stdout (" << fd << ") closed" << oendl; #endif d->notifierStdout->setEnabled( FALSE ); delete d->notifierStdout; d->notifierStdout = 0; ::close( d->proc->socketStdout ); d->proc->socketStdout = 0; return; } else if ( fd == d->proc->socketStderr ) { #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcess::socketRead(): stderr (%d) closed", fd ); + odebug << "QProcess::socketRead(): stderr (" << fd << ") closed" << oendl; #endif d->notifierStderr->setEnabled( FALSE ); delete d->notifierStderr; d->notifierStderr = 0; ::close( d->proc->socketStderr ); d->proc->socketStderr = 0; return; } } // read all data that is available while ( n == bufsize ) { oldSize = buffer->size(); @@ -1052,25 +1051,25 @@ void QProcess::socketRead( int fd ) This private slot is called when the process tries to read data from standard input. */ void QProcess::socketWrite( int fd ) { if ( fd != d->proc->socketStdin || d->proc->socketStdin == 0 ) return; if ( d->stdinBuf.isEmpty() ) { d->notifierStdin->setEnabled( FALSE ); return; } #if defined(QT_QPROCESS_DEBUG) - qDebug( "QProcess::socketWrite(): write to stdin (%d)", fd ); + odebug << "QProcess::socketWrite(): write to stdin (" << fd << ")" << oendl; #endif ssize_t ret = ::write( fd, d->stdinBuf.head()->data() + d->stdinBufRead, d->stdinBuf.head()->size() - d->stdinBufRead ); if ( ret > 0 ) d->stdinBufRead += ret; if ( d->stdinBufRead == (ssize_t)d->stdinBuf.head()->size() ) { d->stdinBufRead = 0; delete d->stdinBuf.dequeue(); if ( wroteToStdinConnected && d->stdinBuf.isEmpty() ) emit wroteToStdin(); socketWrite( fd ); |