src/qt3support/other/q3process_unix.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt3Support module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qplatformdefs.h"
       
    43 
       
    44 // Solaris redefines connect -> __xnet_connect with _XOPEN_SOURCE_EXTENDED.
       
    45 #if defined(connect)
       
    46 #undef connect
       
    47 #endif
       
    48 
       
    49 #include "q3process.h"
       
    50 
       
    51 #ifndef QT_NO_PROCESS
       
    52 
       
    53 #include "qapplication.h"
       
    54 #include "q3cstring.h"
       
    55 #include "q3ptrqueue.h"
       
    56 #include "q3ptrlist.h"
       
    57 #include "qsocketnotifier.h"
       
    58 #include "qtimer.h"
       
    59 #include "q3cleanuphandler.h"
       
    60 #include "qregexp.h"
       
    61 #include "private/q3membuf_p.h"
       
    62 #include "private/qobject_p.h"
       
    63 #include "private/qcore_unix_p.h"
       
    64 
       
    65 #include <stdlib.h>
       
    66 #include <errno.h>
       
    67 #include <sys/types.h>
       
    68 
       
    69 QT_BEGIN_NAMESPACE
       
    70 
       
    71 #ifdef __MIPSEL__
       
    72 # ifndef SOCK_DGRAM
       
    73 #  define SOCK_DGRAM 1
       
    74 # endif
       
    75 # ifndef SOCK_STREAM
       
    76 #  define SOCK_STREAM 2
       
    77 # endif
       
    78 #endif
       
    79 
       
    80 //#define QT_Q3PROCESS_DEBUG
       
    81 
       
    82 
       
    83 #ifdef Q_C_CALLBACKS
       
    84 extern "C" {
       
    85 #endif // Q_C_CALLBACKS
       
    86 
       
    87     static QT_SIGNAL_RETTYPE qt_C_sigchldHnd(QT_SIGNAL_ARGS);
       
    88 
       
    89 #ifdef Q_C_CALLBACKS
       
    90 }
       
    91 #endif // Q_C_CALLBACKS
       
    92 
       
    93 
       
    94 class QProc;
       
    95 class Q3ProcessManager;
       
    96 class Q3ProcessPrivate
       
    97 {
       
    98 public:
       
    99     Q3ProcessPrivate();
       
   100     ~Q3ProcessPrivate();
       
   101 
       
   102     void closeOpenSocketsForChild();
       
   103     void newProc( pid_t pid, Q3Process *process );
       
   104 
       
   105     Q3Membuf bufStdout;
       
   106     Q3Membuf bufStderr;
       
   107 
       
   108     Q3PtrQueue<QByteArray> stdinBuf;
       
   109 
       
   110     QSocketNotifier *notifierStdin;
       
   111     QSocketNotifier *notifierStdout;
       
   112     QSocketNotifier *notifierStderr;
       
   113 
       
   114     ssize_t stdinBufRead;
       
   115     QProc *proc;
       
   116 
       
   117     bool exitValuesCalculated;
       
   118     bool socketReadCalled;
       
   119 
       
   120     static Q3ProcessManager *procManager;
       
   121 };
       
   122 
       
   123 
       
   124 /***********************************************************************
       
   125  *
       
   126  * QProc
       
   127  *
       
   128  **********************************************************************/
       
   129 /*
       
   130   The class Q3Process does not necessarily map exactly to the running
       
   131   child processes: if the process is finished, the Q3Process class may still be
       
   132   there; furthermore a user can use Q3Process to start more than one process.
       
   133 
       
   134   The helper-class QProc has the semantics that one instance of this class maps
       
   135   directly to a running child process.
       
   136 */
       
   137 class QProc
       
   138 {
       
   139 public:
       
   140     QProc( pid_t p, Q3Process *proc=0 ) : pid(p), process(proc)
       
   141     {
       
   142 #if defined(QT_Q3PROCESS_DEBUG)
       
   143 	qDebug( "QProc: Constructor for pid %d and Q3Process %p", pid, process );
       
   144 #endif
       
   145 	socketStdin = 0;
       
   146 	socketStdout = 0;
       
   147 	socketStderr = 0;
       
   148     }
       
   149     ~QProc()
       
   150     {
       
   151 #if defined(QT_Q3PROCESS_DEBUG)
       
   152 	qDebug( "QProc: Destructor for pid %d and Q3Process %p", pid, process );
       
   153 #endif
       
   154 	if ( process ) {
       
   155 	    if ( process->d->notifierStdin )
       
   156 		process->d->notifierStdin->setEnabled( false );
       
   157 	    if ( process->d->notifierStdout )
       
   158 		process->d->notifierStdout->setEnabled( false );
       
   159 	    if ( process->d->notifierStderr )
       
   160 		process->d->notifierStderr->setEnabled( false );
       
   161 	    process->d->proc = 0;
       
   162 	}
       
   163 	if( socketStdin )
       
   164 	    qt_safe_close( socketStdin );
       
   165 	if( socketStdout )
       
   166 	    qt_safe_close( socketStdout );
       
   167 	if( socketStderr )
       
   168 	    qt_safe_close( socketStderr );
       
   169     }
       
   170 
       
   171     pid_t pid;
       
   172     int socketStdin;
       
   173     int socketStdout;
       
   174     int socketStderr;
       
   175     Q3Process *process;
       
   176 };
       
   177 
       
   178 /***********************************************************************
       
   179  *
       
   180  * Q3ProcessManager
       
   181  *
       
   182  **********************************************************************/
       
   183 class Q3ProcessManager : public QObject
       
   184 {
       
   185     Q_OBJECT
       
   186 
       
   187 public:
       
   188     Q3ProcessManager();
       
   189     ~Q3ProcessManager();
       
   190 
       
   191     void append( QProc *p );
       
   192     void remove( QProc *p );
       
   193 
       
   194     void cleanup();
       
   195 
       
   196 public slots:
       
   197     void removeMe();
       
   198     void sigchldHnd( int );
       
   199 
       
   200 public:
       
   201     struct sigaction oldactChld;
       
   202     struct sigaction oldactPipe;
       
   203     Q3PtrList<QProc> *procList;
       
   204     int sigchldFd[2];
       
   205 
       
   206 private:
       
   207     QSocketNotifier *sn;
       
   208 };
       
   209 
       
   210 static void q3process_cleanup()
       
   211 {
       
   212     delete Q3ProcessPrivate::procManager;
       
   213     Q3ProcessPrivate::procManager = 0;
       
   214 }
       
   215 
       
   216 #ifdef Q_OS_QNX6
       
   217 #define BAILOUT qt_safe_close(tmpSocket);qt_safe_close(socketFD[1]);return -1;
       
   218 int qnx6SocketPairReplacement (int socketFD[2]) {
       
   219     int tmpSocket;
       
   220     tmpSocket = socket (AF_INET, SOCK_STREAM, 0);
       
   221     if (tmpSocket == -1)
       
   222 	return -1;
       
   223     socketFD[1] = socket(AF_INET, SOCK_STREAM, 0);
       
   224     if (socketFD[1] == -1) { BAILOUT };
       
   225 
       
   226     sockaddr_in ipAddr;
       
   227     memset(&ipAddr, 0, sizeof(ipAddr));
       
   228     ipAddr.sin_family = AF_INET;
       
   229     ipAddr.sin_addr.s_addr = INADDR_ANY;
       
   230 
       
   231     int socketOptions = 1;
       
   232     setsockopt(tmpSocket, SOL_SOCKET, SO_REUSEADDR, &socketOptions, sizeof(int));
       
   233 
       
   234     bool found = false;
       
   235     for (int socketIP = 2000; (socketIP < 2500) && !(found); socketIP++) {
       
   236 	ipAddr.sin_port = htons(socketIP);
       
   237 	if (bind(tmpSocket, (struct sockaddr *)&ipAddr, sizeof(ipAddr)))
       
   238 	    found = true;
       
   239     }
       
   240 
       
   241     if (listen(tmpSocket, 5)) { BAILOUT };
       
   242 
       
   243     // Select non-blocking mode
       
   244     int originalFlags = fcntl(socketFD[1], F_GETFL, 0);
       
   245     fcntl(socketFD[1], F_SETFL, originalFlags | O_NONBLOCK);
       
   246 
       
   247     // Request connection
       
   248     if (connect(socketFD[1], (struct sockaddr*)&ipAddr, sizeof(ipAddr)))
       
   249 	if (errno != EINPROGRESS) { BAILOUT };
       
   250 
       
   251     // Accept connection
       
   252     socketFD[0] = accept(tmpSocket, (struct sockaddr *)NULL, (size_t *)NULL);
       
   253     if(socketFD[0] == -1) { BAILOUT };
       
   254 
       
   255     // We're done
       
   256     qt_safe_close(tmpSocket);
       
   257 
       
   258     // Restore original flags , ie return to blocking
       
   259     fcntl(socketFD[1], F_SETFL, originalFlags);
       
   260     return 0;
       
   261 }
       
   262 #undef BAILOUT
       
   263 #endif
       
   264 
       
   265 Q3ProcessManager::Q3ProcessManager() : sn(0)
       
   266 {
       
   267     procList = new Q3PtrList<QProc>;
       
   268     procList->setAutoDelete( true );
       
   269 
       
   270     // The SIGCHLD handler writes to a socket to tell the manager that
       
   271     // something happened. This is done to get the processing in sync with the
       
   272     // event reporting.
       
   273 #ifndef Q_OS_QNX6
       
   274     if ( ::socketpair( AF_UNIX, SOCK_STREAM, 0, sigchldFd ) ) {
       
   275 #else
       
   276     if ( qnx6SocketPairReplacement (sigchldFd) ) {
       
   277 #endif
       
   278 	sigchldFd[0] = 0;
       
   279 	sigchldFd[1] = 0;
       
   280     } else {
       
   281 #if defined(QT_Q3PROCESS_DEBUG)
       
   282 	qDebug( "Q3ProcessManager: install socket notifier (%d)", sigchldFd[1] );
       
   283 #endif
       
   284 	sn = new QSocketNotifier( sigchldFd[1],
       
   285 		QSocketNotifier::Read, this );
       
   286 	connect( sn, SIGNAL(activated(int)),
       
   287 		this, SLOT(sigchldHnd(int)) );
       
   288 	sn->setEnabled( true );
       
   289     }
       
   290 
       
   291     // install a SIGCHLD handler and ignore SIGPIPE
       
   292     struct sigaction act;
       
   293 
       
   294 #if defined(QT_Q3PROCESS_DEBUG)
       
   295     qDebug( "Q3ProcessManager: install a SIGCHLD handler" );
       
   296 #endif
       
   297     act.sa_handler = qt_C_sigchldHnd;
       
   298     sigemptyset( &(act.sa_mask) );
       
   299     sigaddset( &(act.sa_mask), SIGCHLD );
       
   300     act.sa_flags = SA_NOCLDSTOP;
       
   301 #if defined(SA_RESTART)
       
   302     act.sa_flags |= SA_RESTART;
       
   303 #endif
       
   304     if ( sigaction( SIGCHLD, &act, &oldactChld ) != 0 )
       
   305 	qWarning( "Error installing SIGCHLD handler" );
       
   306 
       
   307 #if defined(QT_Q3PROCESS_DEBUG)
       
   308     qDebug( "Q3ProcessManager: install a SIGPIPE handler (SIG_IGN)" );
       
   309 #endif
       
   310     act.sa_handler = QT_SIGNAL_IGNORE;
       
   311     sigemptyset( &(act.sa_mask) );
       
   312     sigaddset( &(act.sa_mask), SIGPIPE );
       
   313     act.sa_flags = 0;
       
   314     if ( sigaction( SIGPIPE, &act, &oldactPipe ) != 0 )
       
   315 	qWarning( "Error installing SIGPIPE handler" );
       
   316 }
       
   317 
       
   318 Q3ProcessManager::~Q3ProcessManager()
       
   319 {
       
   320     delete procList;
       
   321 
       
   322     if ( sigchldFd[0] != 0 )
       
   323 	qt_safe_close( sigchldFd[0] );
       
   324     if ( sigchldFd[1] != 0 )
       
   325 	qt_safe_close( sigchldFd[1] );
       
   326 
       
   327     // restore SIGCHLD handler
       
   328 #if defined(QT_Q3PROCESS_DEBUG)
       
   329     qDebug( "Q3ProcessManager: restore old sigchild handler" );
       
   330 #endif
       
   331     if ( sigaction( SIGCHLD, &oldactChld, 0 ) != 0 )
       
   332 	qWarning( "Error restoring SIGCHLD handler" );
       
   333 
       
   334 #if defined(QT_Q3PROCESS_DEBUG)
       
   335     qDebug( "Q3ProcessManager: restore old sigpipe handler" );
       
   336 #endif
       
   337     if ( sigaction( SIGPIPE, &oldactPipe, 0 ) != 0 )
       
   338 	qWarning( "Error restoring SIGPIPE handler" );
       
   339 }
       
   340 
       
   341 void Q3ProcessManager::append( QProc *p )
       
   342 {
       
   343     procList->append( p );
       
   344 #if defined(QT_Q3PROCESS_DEBUG)
       
   345     qDebug( "Q3ProcessManager: append process (procList.count(): %d)", procList->count() );
       
   346 #endif
       
   347 }
       
   348 
       
   349 void Q3ProcessManager::remove( QProc *p )
       
   350 {
       
   351     procList->remove( p );
       
   352 #if defined(QT_Q3PROCESS_DEBUG)
       
   353     qDebug( "Q3ProcessManager: remove process (procList.count(): %d)", procList->count() );
       
   354 #endif
       
   355     cleanup();
       
   356 }
       
   357 
       
   358 void Q3ProcessManager::cleanup()
       
   359 {
       
   360     if ( procList->count() == 0 ) {
       
   361 	QTimer::singleShot( 0, this, SLOT(removeMe()) );
       
   362     }
       
   363 }
       
   364 
       
   365 void Q3ProcessManager::removeMe()
       
   366 {
       
   367     if ( procList->count() == 0 ) {
       
   368 	qRemovePostRoutine(q3process_cleanup);
       
   369 	Q3ProcessPrivate::procManager = 0;
       
   370 	delete this;
       
   371     }
       
   372 }
       
   373 
       
   374 void Q3ProcessManager::sigchldHnd( int fd )
       
   375 {
       
   376     // Disable the socket notifier to make sure that this function is not
       
   377     // called recursively -- this can happen, if you enter the event loop in
       
   378     // the slot connected to the processExited() signal (e.g. by showing a
       
   379     // modal dialog) and there are more than one process which exited in the
       
   380     // meantime.
       
   381     if ( sn ) {
       
   382 	if ( !sn->isEnabled() )
       
   383 	    return;
       
   384 	sn->setEnabled( false );
       
   385     }
       
   386 
       
   387     char tmp;
       
   388     qt_safe_read( fd, &tmp, sizeof(tmp) );
       
   389 #if defined(QT_Q3PROCESS_DEBUG)
       
   390     qDebug( "Q3ProcessManager::sigchldHnd()" );
       
   391 #endif
       
   392     QProc *proc;
       
   393     Q3Process *process;
       
   394     bool removeProc;
       
   395     proc = procList->first();
       
   396     while ( proc != 0 ) {
       
   397 	removeProc = false;
       
   398 	process = proc->process;
       
   399 	if ( process != 0 ) {
       
   400 	    if ( !process->isRunning() ) {
       
   401 #if defined(QT_Q3PROCESS_DEBUG)
       
   402 		qDebug( "Q3ProcessManager::sigchldHnd() (PID: %d): process exited (Q3Process available)", proc->pid );
       
   403 #endif
       
   404 		/*
       
   405 		  Apparently, there is not consistency among different
       
   406 		  operating systems on how to use FIONREAD.
       
   407 
       
   408 		  FreeBSD, Linux and Solaris all expect the 3rd
       
   409 		  argument to ioctl() to be an int, which is normally
       
   410 		  32-bit even on 64-bit machines.
       
   411 
       
   412 		  IRIX, on the other hand, expects a size_t, which is
       
   413 		  64-bit on 64-bit machines.
       
   414 
       
   415 		  So, the solution is to use size_t initialized to
       
   416 		  zero to make sure all bits are set to zero,
       
   417 		  preventing underflow with the FreeBSD/Linux/Solaris
       
   418 		  ioctls.
       
   419 		*/
       
   420 		size_t nbytes = 0;
       
   421 		// read pending data
       
   422 		if ( proc->socketStdout && ::ioctl(proc->socketStdout, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) {
       
   423 #if defined(QT_Q3PROCESS_DEBUG)
       
   424 		    qDebug( "Q3ProcessManager::sigchldHnd() (PID: %d): reading %d bytes of pending data on stdout", proc->pid, nbytes );
       
   425 #endif
       
   426 		    process->socketRead( proc->socketStdout );
       
   427 		}
       
   428 		nbytes = 0;
       
   429 		if ( proc->socketStderr && ::ioctl(proc->socketStderr, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) {
       
   430 #if defined(QT_Q3PROCESS_DEBUG)
       
   431 		    qDebug( "Q3ProcessManager::sigchldHnd() (PID: %d): reading %d bytes of pending data on stderr", proc->pid, nbytes );
       
   432 #endif
       
   433 		    process->socketRead( proc->socketStderr );
       
   434 		}
       
   435 		// close filedescriptors if open, and disable the
       
   436 		// socket notifiers
       
   437 		if ( proc->socketStdout ) {
       
   438 		    qt_safe_close( proc->socketStdout );
       
   439 		    proc->socketStdout = 0;
       
   440 		    if (process->d->notifierStdout)
       
   441 			process->d->notifierStdout->setEnabled(false);
       
   442 		}
       
   443 		if ( proc->socketStderr ) {
       
   444 		    qt_safe_close( proc->socketStderr );
       
   445 		    proc->socketStderr = 0;
       
   446 		    if (process->d->notifierStderr)
       
   447 			process->d->notifierStderr->setEnabled(false);
       
   448 		}
       
   449 
       
   450 		if ( process->notifyOnExit )
       
   451 		    emit process->processExited();
       
   452 
       
   453 		removeProc = true;
       
   454 	    }
       
   455 	} else {
       
   456 	    int status;
       
   457 	    if ( ::waitpid( proc->pid, &status, WNOHANG ) == proc->pid ) {
       
   458 #if defined(QT_Q3PROCESS_DEBUG)
       
   459 		qDebug( "Q3ProcessManager::sigchldHnd() (PID: %d): process exited (Q3Process not available)", proc->pid );
       
   460 #endif
       
   461 		removeProc = true;
       
   462 	    }
       
   463 	}
       
   464 	if ( removeProc ) {
       
   465 	    QProc *oldproc = proc;
       
   466 	    proc = procList->next();
       
   467 	    remove( oldproc );
       
   468 	} else {
       
   469 	    proc = procList->next();
       
   470 	}
       
   471     }
       
   472     if ( sn )
       
   473 	sn->setEnabled( true );
       
   474 }
       
   475 
       
   476 QT_BEGIN_INCLUDE_NAMESPACE
       
   477 #include "q3process_unix.moc"
       
   478 QT_END_INCLUDE_NAMESPACE
       
   479 
       
   480 
       
   481 /***********************************************************************
       
   482  *
       
   483  * Q3ProcessPrivate
       
   484  *
       
   485  **********************************************************************/
       
   486 Q3ProcessManager *Q3ProcessPrivate::procManager = 0;
       
   487 
       
   488 Q3ProcessPrivate::Q3ProcessPrivate()
       
   489 {
       
   490 #if defined(QT_Q3PROCESS_DEBUG)
       
   491     qDebug( "Q3ProcessPrivate: Constructor" );
       
   492 #endif
       
   493     stdinBufRead = 0;
       
   494 
       
   495     notifierStdin = 0;
       
   496     notifierStdout = 0;
       
   497     notifierStderr = 0;
       
   498 
       
   499     exitValuesCalculated = false;
       
   500     socketReadCalled = false;
       
   501 
       
   502     proc = 0;
       
   503 }
       
   504 
       
   505 Q3ProcessPrivate::~Q3ProcessPrivate()
       
   506 {
       
   507 #if defined(QT_Q3PROCESS_DEBUG)
       
   508     qDebug( "Q3ProcessPrivate: Destructor" );
       
   509 #endif
       
   510 
       
   511     if ( proc != 0 ) {
       
   512 	if ( proc->socketStdin != 0 ) {
       
   513 	    qt_safe_close( proc->socketStdin );
       
   514 	    proc->socketStdin = 0;
       
   515 	}
       
   516 	proc->process = 0;
       
   517     }
       
   518 
       
   519     while ( !stdinBuf.isEmpty() ) {
       
   520 	delete stdinBuf.dequeue();
       
   521     }
       
   522     delete notifierStdin;
       
   523     delete notifierStdout;
       
   524     delete notifierStderr;
       
   525 }
       
   526 
       
   527 /*
       
   528   Closes all open sockets in the child process that are not needed by the child
       
   529   process. Otherwise one child may have an open socket on standard input, etc.
       
   530   of another child.
       
   531 */
       
   532 void Q3ProcessPrivate::closeOpenSocketsForChild()
       
   533 {
       
   534     if ( procManager != 0 ) {
       
   535 	if ( procManager->sigchldFd[0] != 0 )
       
   536 	    qt_safe_close( procManager->sigchldFd[0] );
       
   537 	if ( procManager->sigchldFd[1] != 0 )
       
   538 	    qt_safe_close( procManager->sigchldFd[1] );
       
   539 
       
   540 	// close also the sockets from other Q3Process instances
       
   541 	for ( QProc *p=procManager->procList->first(); p!=0; p=procManager->procList->next() ) {
       
   542 	    qt_safe_close( p->socketStdin );
       
   543 	    qt_safe_close( p->socketStdout );
       
   544 	    qt_safe_close( p->socketStderr );
       
   545 	}
       
   546     }
       
   547 }
       
   548 
       
   549 void Q3ProcessPrivate::newProc( pid_t pid, Q3Process *process )
       
   550 {
       
   551     proc = new QProc( pid, process );
       
   552     if ( procManager == 0 ) {
       
   553 	procManager = new Q3ProcessManager;
       
   554 	qAddPostRoutine(q3process_cleanup);
       
   555     }
       
   556     // the Q3ProcessManager takes care of deleting the QProc instances
       
   557     procManager->append( proc );
       
   558 }
       
   559 
       
   560 /***********************************************************************
       
   561  *
       
   562  * sigchld handler callback
       
   563  *
       
   564  **********************************************************************/
       
   565 static QT_SIGNAL_RETTYPE qt_C_sigchldHnd(QT_SIGNAL_ARGS)
       
   566 {
       
   567     if ( Q3ProcessPrivate::procManager == 0 )
       
   568 	return;
       
   569     if ( Q3ProcessPrivate::procManager->sigchldFd[0] == 0 )
       
   570 	return;
       
   571 
       
   572     char a = 1;
       
   573     qt_safe_write( Q3ProcessPrivate::procManager->sigchldFd[0], &a, sizeof(a) );
       
   574 }
       
   575 
       
   576 
       
   577 /***********************************************************************
       
   578  *
       
   579  * Q3Process
       
   580  *
       
   581  **********************************************************************/
       
   582 /*
       
   583   This private class does basic initialization.
       
   584 */
       
   585 void Q3Process::init()
       
   586 {
       
   587     d = new Q3ProcessPrivate();
       
   588     exitStat = 0;
       
   589     exitNormal = false;
       
   590 }
       
   591 
       
   592 /*
       
   593   This private class resets the process variables, etc. so that it can be used
       
   594   for another process to start.
       
   595 */
       
   596 void Q3Process::reset()
       
   597 {
       
   598     delete d;
       
   599     d = new Q3ProcessPrivate();
       
   600     exitStat = 0;
       
   601     exitNormal = false;
       
   602     d->bufStdout.clear();
       
   603     d->bufStderr.clear();
       
   604 }
       
   605 
       
   606 Q3Membuf* Q3Process::membufStdout()
       
   607 {
       
   608     if ( d->proc && d->proc->socketStdout ) {
       
   609 	/*
       
   610 	  Apparently, there is not consistency among different
       
   611 	  operating systems on how to use FIONREAD.
       
   612 
       
   613 	  FreeBSD, Linux and Solaris all expect the 3rd argument to
       
   614 	  ioctl() to be an int, which is normally 32-bit even on
       
   615 	  64-bit machines.
       
   616 
       
   617 	  IRIX, on the other hand, expects a size_t, which is 64-bit
       
   618 	  on 64-bit machines.
       
   619 
       
   620 	  So, the solution is to use size_t initialized to zero to
       
   621 	  make sure all bits are set to zero, preventing underflow
       
   622 	  with the FreeBSD/Linux/Solaris ioctls.
       
   623 	*/
       
   624 	size_t nbytes = 0;
       
   625 	if ( ::ioctl(d->proc->socketStdout, FIONREAD, (char*)&nbytes)==0 && nbytes>0 )
       
   626 	    socketRead( d->proc->socketStdout );
       
   627     }
       
   628     return &d->bufStdout;
       
   629 }
       
   630 
       
   631 Q3Membuf* Q3Process::membufStderr()
       
   632 {
       
   633     if ( d->proc && d->proc->socketStderr ) {
       
   634 	/*
       
   635 	  Apparently, there is not consistency among different
       
   636 	  operating systems on how to use FIONREAD.
       
   637 
       
   638 	  FreeBSD, Linux and Solaris all expect the 3rd argument to
       
   639 	  ioctl() to be an int, which is normally 32-bit even on
       
   640 	  64-bit machines.
       
   641 
       
   642 	  IRIX, on the other hand, expects a size_t, which is 64-bit
       
   643 	  on 64-bit machines.
       
   644 
       
   645 	  So, the solution is to use size_t initialized to zero to
       
   646 	  make sure all bits are set to zero, preventing underflow
       
   647 	  with the FreeBSD/Linux/Solaris ioctls.
       
   648 	*/
       
   649 	size_t nbytes = 0;
       
   650 	if ( ::ioctl(d->proc->socketStderr, FIONREAD, (char*)&nbytes)==0 && nbytes>0 )
       
   651 	    socketRead( d->proc->socketStderr );
       
   652     }
       
   653     return &d->bufStderr;
       
   654 }
       
   655 
       
   656 Q3Process::~Q3Process()
       
   657 {
       
   658     delete d;
       
   659 }
       
   660 
       
   661 bool Q3Process::start( QStringList *env )
       
   662 {
       
   663 #if defined(QT_Q3PROCESS_DEBUG)
       
   664     qDebug( "Q3Process::start()" );
       
   665 #endif
       
   666     reset();
       
   667 
       
   668     int sStdin[2];
       
   669     int sStdout[2];
       
   670     int sStderr[2];
       
   671 
       
   672     // open sockets for piping
       
   673 #ifndef Q_OS_QNX6
       
   674     if ( (comms & Stdin) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdin ) == -1 ) {
       
   675 #else
       
   676     if ( (comms & Stdin) && qnx6SocketPairReplacement(sStdin) == -1 ) {
       
   677 #endif
       
   678 	return false;
       
   679     }
       
   680 #ifndef Q_OS_QNX6
       
   681     if ( (comms & Stderr) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStderr ) == -1 ) {
       
   682 #else
       
   683     if ( (comms & Stderr) && qnx6SocketPairReplacement(sStderr) == -1 ) {
       
   684 #endif
       
   685 	if ( comms & Stdin ) {
       
   686 	    qt_safe_close( sStdin[0] );
       
   687 	    qt_safe_close( sStdin[1] );
       
   688 	}
       
   689 	return false;
       
   690     }
       
   691 #ifndef Q_OS_QNX6
       
   692     if ( (comms & Stdout) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdout ) == -1 ) {
       
   693 #else
       
   694     if ( (comms & Stdout) && qnx6SocketPairReplacement(sStdout) == -1 ) {
       
   695 #endif
       
   696 	if ( comms & Stdin ) {
       
   697 	    qt_safe_close( sStdin[0] );
       
   698 	    qt_safe_close( sStdin[1] );
       
   699 	}
       
   700 	if ( comms & Stderr ) {
       
   701 	    qt_safe_close( sStderr[0] );
       
   702 	    qt_safe_close( sStderr[1] );
       
   703 	}
       
   704 	return false;
       
   705     }
       
   706 
       
   707     // the following pipe is only used to determine if the process could be
       
   708     // started
       
   709     int fd[2];
       
   710     if ( pipe( fd ) < 0 ) {
       
   711 	// non critical error, go on
       
   712 	fd[0] = 0;
       
   713 	fd[1] = 0;
       
   714     }
       
   715 
       
   716     // construct the arguments for exec
       
   717     Q3CString *arglistQ = new Q3CString[ _arguments.count() + 1 ];
       
   718     const char** arglist = new const char*[ _arguments.count() + 1 ];
       
   719     int i = 0;
       
   720     for ( QStringList::Iterator it = _arguments.begin(); it != _arguments.end(); ++it ) {
       
   721 	arglistQ[i] = (*it).local8Bit();
       
   722 	arglist[i] = arglistQ[i];
       
   723 #if defined(QT_Q3PROCESS_DEBUG)
       
   724 	qDebug( "Q3Process::start(): arg %d = %s", i, arglist[i] );
       
   725 #endif
       
   726 	i++;
       
   727     }
       
   728 #ifdef Q_OS_MACX
       
   729     if(i) {
       
   730 	Q3CString arg_bundle = arglistQ[0];
       
   731 	QFileInfo fi(QString::fromUtf8(arg_bundle.constData()));
       
   732 	if(fi.exists() && fi.isDir() && arg_bundle.right(4) == ".app") {
       
   733 	    Q3CString exe = arg_bundle;
       
   734 	    int lslash = exe.findRev('/');
       
   735 	    if(lslash != -1)
       
   736 		exe = exe.mid(lslash+1);
       
   737 	    exe = Q3CString(arg_bundle + "/Contents/MacOS/" + exe);
       
   738 	    exe = exe.left(exe.length() - 4); //chop off the .app
       
   739 	    if(QFile::exists(QString::fromLatin1(exe.constData()))) {
       
   740 		arglistQ[0] = exe;
       
   741 		arglist[0] = arglistQ[0];
       
   742 	    }
       
   743 	}
       
   744     }
       
   745 #endif
       
   746     arglist[i] = 0;
       
   747 
       
   748     // Must make sure signal handlers are installed before exec'ing
       
   749     // in case the process exits quickly.
       
   750     if ( d->procManager == 0 ) {
       
   751 	d->procManager = new Q3ProcessManager;
       
   752 	qAddPostRoutine(q3process_cleanup);
       
   753     }
       
   754 
       
   755     // fork and exec
       
   756     QApplication::flushX();
       
   757     pid_t pid = fork();
       
   758     if ( pid == 0 ) {
       
   759 	// child
       
   760 	d->closeOpenSocketsForChild();
       
   761 	if ( comms & Stdin ) {
       
   762 	    qt_safe_close( sStdin[1] );
       
   763 	    ::dup2( sStdin[0], STDIN_FILENO );
       
   764 	}
       
   765 	if ( comms & Stdout ) {
       
   766 	    qt_safe_close( sStdout[0] );
       
   767 	    ::dup2( sStdout[1], STDOUT_FILENO );
       
   768 	}
       
   769 	if ( comms & Stderr ) {
       
   770 	    qt_safe_close( sStderr[0] );
       
   771 	    ::dup2( sStderr[1], STDERR_FILENO );
       
   772 	}
       
   773 	if ( comms & DupStderr ) {
       
   774 	    ::dup2( STDOUT_FILENO, STDERR_FILENO );
       
   775 	}
       
   776 #ifndef QT_NO_DIR
       
   777 	::chdir( workingDir.absPath().latin1() );
       
   778 #endif
       
   779 	if ( fd[0] )
       
   780 	    qt_safe_close( fd[0] );
       
   781 	if ( fd[1] )
       
   782 	    ::fcntl( fd[1], F_SETFD, FD_CLOEXEC ); // close on exec shows success
       
   783 
       
   784 	if ( env == 0 ) { // inherit environment and start process
       
   785 #ifndef Q_OS_QNX4
       
   786 	    ::execvp( arglist[0], (char*const*)arglist ); // ### cast not nice
       
   787 #else
       
   788 	    ::execvp( arglist[0], (char const*const*)arglist ); // ### cast not nice
       
   789 #endif
       
   790 	} else { // start process with environment settins as specified in env
       
   791 	    // construct the environment for exec
       
   792 	    int numEntries = env->count();
       
   793 #if defined(Q_OS_MACX)
       
   794 	    QString ld_library_path(QLatin1String("DYLD_LIBRARY_PATH"));
       
   795 #else
       
   796 	    QString ld_library_path(QLatin1String("LD_LIBRARY_PATH"));
       
   797 #endif
       
   798 	    bool setLibraryPath =
       
   799 		env->grep( QRegExp( QLatin1Char('^') + ld_library_path + QLatin1Char('=') ) ).empty() &&
       
   800 		getenv( ld_library_path.local8Bit() ) != 0;
       
   801 	    if ( setLibraryPath )
       
   802 		numEntries++;
       
   803 	    Q3CString *envlistQ = new Q3CString[ numEntries + 1 ];
       
   804 	    const char** envlist = new const char*[ numEntries + 1 ];
       
   805 	    int i = 0;
       
   806 	    if ( setLibraryPath ) {
       
   807 		envlistQ[i] = QString( ld_library_path + QLatin1String("=%1") ).arg( QString::fromLocal8Bit(getenv( ld_library_path.local8Bit() )) ).local8Bit();
       
   808 		envlist[i] = envlistQ[i];
       
   809 		i++;
       
   810 	    }
       
   811 	    for ( QStringList::Iterator it = env->begin(); it != env->end(); ++it ) {
       
   812 		envlistQ[i] = (*it).local8Bit();
       
   813 		envlist[i] = envlistQ[i];
       
   814 		i++;
       
   815 	    }
       
   816 	    envlist[i] = 0;
       
   817 
       
   818 	    // look for the executable in the search path
       
   819 	    if ( _arguments.count()>0 && getenv("PATH")!=0 ) {
       
   820 		QString command = _arguments[0];
       
   821 		if ( !command.contains( QLatin1Char('/') ) ) {
       
   822 		    QStringList pathList = QStringList::split( QLatin1Char(':'), QString::fromLocal8Bit(getenv( "PATH" )) );
       
   823 		    for (QStringList::Iterator it = pathList.begin(); it != pathList.end(); ++it ) {
       
   824 			QString dir = *it;
       
   825 #if defined(Q_OS_MACX) //look in a bundle
       
   826 			if(!QFile::exists(dir + QLatin1Char('/') + command) && QFile::exists(dir + QLatin1Char('/') + command + QLatin1String(".app")))
       
   827 			    dir += QLatin1Char('/') + command + QLatin1String(".app/Contents/MacOS");
       
   828 #endif
       
   829 #ifndef QT_NO_DIR
       
   830 			QFileInfo fileInfo( dir, command );
       
   831 #else
       
   832 			QFileInfo fileInfo( dir + QLatin1Char('/') + command );
       
   833 #endif
       
   834 			if ( fileInfo.isExecutable() ) {
       
   835 #if defined(Q_OS_MACX)
       
   836 			    arglistQ[0] = fileInfo.absFilePath().local8Bit();
       
   837 #else
       
   838 			    arglistQ[0] = fileInfo.filePath().local8Bit();
       
   839 #endif
       
   840 			    arglist[0] = arglistQ[0];
       
   841 			    break;
       
   842 			}
       
   843 		    }
       
   844 		}
       
   845 	    }
       
   846 #ifndef Q_OS_QNX4
       
   847 	    ::execve( arglist[0], (char*const*)arglist, (char*const*)envlist ); // ### casts not nice
       
   848 #else
       
   849 	    ::execve( arglist[0], (char const*const*)arglist,(char const*const*)envlist ); // ### casts not nice
       
   850 #endif
       
   851 	}
       
   852 	if ( fd[1] ) {
       
   853 	    char buf = 0;
       
   854 	    qt_safe_write( fd[1], &buf, 1 );
       
   855 	    qt_safe_close( fd[1] );
       
   856 	}
       
   857 	::_exit( -1 );
       
   858     } else if ( pid == -1 ) {
       
   859 	// error forking
       
   860 	goto error;
       
   861     }
       
   862 
       
   863     // test if exec was successful
       
   864     if ( fd[1] )
       
   865 	qt_safe_close( fd[1] );
       
   866     if ( fd[0] ) {
       
   867 	char buf;
       
   868 	for ( ;; ) {
       
   869 	    int n = ::read( fd[0], &buf, 1 );
       
   870 	    if ( n==1 ) {
       
   871 		// socket was not closed => error
       
   872 		if ( ::waitpid( pid, 0, WNOHANG ) != pid ) {
       
   873 		    // The wait did not succeed yet, so try again when we get
       
   874 		    // the sigchild (to avoid zombies).
       
   875 		    d->newProc( pid, 0 );
       
   876 		}
       
   877 		d->proc = 0;
       
   878 		goto error;
       
   879 	    } else if ( n==-1 ) {
       
   880 		if ( errno==EAGAIN || errno==EINTR )
       
   881 		    // try it again
       
   882 		    continue;
       
   883 	    }
       
   884 	    break;
       
   885 	}
       
   886 	qt_safe_close( fd[0] );
       
   887     }
       
   888 
       
   889     d->newProc( pid, this );
       
   890 
       
   891     if ( comms & Stdin ) {
       
   892 	qt_safe_close( sStdin[0] );
       
   893 	d->proc->socketStdin = sStdin[1];
       
   894 
       
   895 	// Select non-blocking mode
       
   896 	int originalFlags = fcntl(d->proc->socketStdin, F_GETFL, 0);
       
   897 	fcntl(d->proc->socketStdin, F_SETFL, originalFlags | O_NONBLOCK);
       
   898 
       
   899 	d->notifierStdin = new QSocketNotifier( sStdin[1], QSocketNotifier::Write );
       
   900 	connect( d->notifierStdin, SIGNAL(activated(int)),
       
   901 		this, SLOT(socketWrite(int)) );
       
   902 	// setup notifiers for the sockets
       
   903 	if ( !d->stdinBuf.isEmpty() ) {
       
   904 	    d->notifierStdin->setEnabled( true );
       
   905 	}
       
   906     }
       
   907     if ( comms & Stdout ) {
       
   908 	qt_safe_close( sStdout[1] );
       
   909 	d->proc->socketStdout = sStdout[0];
       
   910 	d->notifierStdout = new QSocketNotifier( sStdout[0], QSocketNotifier::Read );
       
   911 	connect( d->notifierStdout, SIGNAL(activated(int)),
       
   912 		this, SLOT(socketRead(int)) );
       
   913 	if ( ioRedirection )
       
   914 	    d->notifierStdout->setEnabled( true );
       
   915     }
       
   916     if ( comms & Stderr ) {
       
   917 	qt_safe_close( sStderr[1] );
       
   918 	d->proc->socketStderr = sStderr[0];
       
   919 	d->notifierStderr = new QSocketNotifier( sStderr[0], QSocketNotifier::Read );
       
   920 	connect( d->notifierStderr, SIGNAL(activated(int)),
       
   921 		this, SLOT(socketRead(int)) );
       
   922 	if ( ioRedirection )
       
   923 	    d->notifierStderr->setEnabled( true );
       
   924     }
       
   925 
       
   926     // cleanup and return
       
   927     delete[] arglistQ;
       
   928     delete[] arglist;
       
   929     return true;
       
   930 
       
   931 error:
       
   932 #if defined(QT_Q3PROCESS_DEBUG)
       
   933     qDebug( "Q3Process::start(): error starting process" );
       
   934 #endif
       
   935     if ( d->procManager )
       
   936 	d->procManager->cleanup();
       
   937     if ( comms & Stdin ) {
       
   938 	qt_safe_close( sStdin[1] );
       
   939 	qt_safe_close( sStdin[0] );
       
   940     }
       
   941     if ( comms & Stdout ) {
       
   942 	qt_safe_close( sStdout[0] );
       
   943 	qt_safe_close( sStdout[1] );
       
   944     }
       
   945     if ( comms & Stderr ) {
       
   946 	qt_safe_close( sStderr[0] );
       
   947 	qt_safe_close( sStderr[1] );
       
   948     }
       
   949     qt_safe_close( fd[0] );
       
   950     qt_safe_close( fd[1] );
       
   951     delete[] arglistQ;
       
   952     delete[] arglist;
       
   953     return false;
       
   954 }
       
   955 
       
   956 
       
   957 void Q3Process::tryTerminate() const
       
   958 {
       
   959     if ( d->proc != 0 )
       
   960 	::kill( d->proc->pid, SIGTERM );
       
   961 }
       
   962 
       
   963 void Q3Process::kill() const
       
   964 {
       
   965     if ( d->proc != 0 )
       
   966 	::kill( d->proc->pid, SIGKILL );
       
   967 }
       
   968 
       
   969 bool Q3Process::isRunning() const
       
   970 {
       
   971     if ( d->exitValuesCalculated ) {
       
   972 #if defined(QT_Q3PROCESS_DEBUG)
       
   973 	qDebug( "Q3Process::isRunning(): false (already computed)" );
       
   974 #endif
       
   975 	return false;
       
   976     }
       
   977     if ( d->proc == 0 )
       
   978 	return false;
       
   979     int status;
       
   980     if ( ::waitpid( d->proc->pid, &status, WNOHANG ) == d->proc->pid ) {
       
   981 	// compute the exit values
       
   982 	Q3Process *that = (Q3Process*)this; // mutable
       
   983 	that->exitNormal = WIFEXITED( status ) != 0;
       
   984 	if ( exitNormal ) {
       
   985 	    that->exitStat = (char)WEXITSTATUS( status );
       
   986 	}
       
   987 	d->exitValuesCalculated = true;
       
   988 
       
   989 	// On heavy processing, the socket notifier for the sigchild might not
       
   990 	// have found time to fire yet.
       
   991 	if ( d->procManager && d->procManager->sigchldFd[1] < FD_SETSIZE ) {
       
   992 	    fd_set fds;
       
   993 	    struct timeval tv;
       
   994 	    FD_ZERO( &fds );
       
   995 	    FD_SET( d->procManager->sigchldFd[1], &fds );
       
   996 	    tv.tv_sec = 0;
       
   997 	    tv.tv_usec = 0;
       
   998 	    if ( ::select( d->procManager->sigchldFd[1]+1, &fds, 0, 0, &tv ) > 0 )
       
   999 		d->procManager->sigchldHnd( d->procManager->sigchldFd[1] );
       
  1000 	}
       
  1001 
       
  1002 #if defined(QT_Q3PROCESS_DEBUG)
       
  1003 	qDebug( "Q3Process::isRunning() (PID: %d): false", d->proc->pid );
       
  1004 #endif
       
  1005 	return false;
       
  1006     }
       
  1007 #if defined(QT_Q3PROCESS_DEBUG)
       
  1008     qDebug( "Q3Process::isRunning() (PID: %d): true", d->proc->pid );
       
  1009 #endif
       
  1010     return true;
       
  1011 }
       
  1012 
       
  1013 bool Q3Process::canReadLineStdout() const
       
  1014 {
       
  1015     if ( !d->proc || !d->proc->socketStdout )
       
  1016 	return d->bufStdout.size() != 0;
       
  1017 
       
  1018     Q3Process *that = (Q3Process*)this;
       
  1019     return that->membufStdout()->scanNewline( 0 );
       
  1020 }
       
  1021 
       
  1022 bool Q3Process::canReadLineStderr() const
       
  1023 {
       
  1024     if ( !d->proc || !d->proc->socketStderr )
       
  1025 	return d->bufStderr.size() != 0;
       
  1026 
       
  1027     Q3Process *that = (Q3Process*)this;
       
  1028     return that->membufStderr()->scanNewline( 0 );
       
  1029 }
       
  1030 
       
  1031 void Q3Process::writeToStdin( const QByteArray& buf )
       
  1032 {
       
  1033 #if defined(QT_Q3PROCESS_DEBUG)
       
  1034 //    qDebug( "Q3Process::writeToStdin(): write to stdin (%d)", d->socketStdin );
       
  1035 #endif
       
  1036     d->stdinBuf.enqueue( new QByteArray(buf) );
       
  1037     if ( d->notifierStdin != 0 )
       
  1038 	d->notifierStdin->setEnabled( true );
       
  1039 }
       
  1040 
       
  1041 
       
  1042 void Q3Process::closeStdin()
       
  1043 {
       
  1044     if ( d->proc == 0 )
       
  1045 	return;
       
  1046     if ( d->proc->socketStdin !=0 ) {
       
  1047 	while ( !d->stdinBuf.isEmpty() ) {
       
  1048 	    delete d->stdinBuf.dequeue();
       
  1049 	}
       
  1050 	d->notifierStdin->setEnabled(false);
       
  1051 	qDeleteInEventHandler(d->notifierStdin);
       
  1052 	d->notifierStdin = 0;
       
  1053 	if ( qt_safe_close( d->proc->socketStdin ) != 0 ) {
       
  1054 	    qWarning( "Could not close stdin of child process" );
       
  1055 	}
       
  1056 #if defined(QT_Q3PROCESS_DEBUG)
       
  1057 	qDebug( "Q3Process::closeStdin(): stdin (%d) closed", d->proc->socketStdin );
       
  1058 #endif
       
  1059 	d->proc->socketStdin = 0;
       
  1060     }
       
  1061 }
       
  1062 
       
  1063 
       
  1064 /*
       
  1065   This private slot is called when the process has outputted data to either
       
  1066   standard output or standard error.
       
  1067 */
       
  1068 void Q3Process::socketRead( int fd )
       
  1069 {
       
  1070     if ( d->socketReadCalled ) {
       
  1071 	// the slots that are connected to the readyRead...() signals might
       
  1072 	// trigger a recursive call of socketRead(). Avoid this since you get a
       
  1073 	// blocking read otherwise.
       
  1074 	return;
       
  1075     }
       
  1076 
       
  1077 #if defined(QT_Q3PROCESS_DEBUG)
       
  1078     qDebug( "Q3Process::socketRead(): %d", fd );
       
  1079 #endif
       
  1080     if ( fd == 0 )
       
  1081 	return;
       
  1082     if ( !d->proc )
       
  1083 	return;
       
  1084     Q3Membuf *buffer = 0;
       
  1085     int n;
       
  1086     if ( fd == d->proc->socketStdout ) {
       
  1087 	buffer = &d->bufStdout;
       
  1088     } else if ( fd == d->proc->socketStderr ) {
       
  1089 	buffer = &d->bufStderr;
       
  1090     } else {
       
  1091 	// this case should never happen, but just to be safe
       
  1092 	return;
       
  1093     }
       
  1094 #if defined(QT_Q3PROCESS_DEBUG)
       
  1095     uint oldSize = buffer->size();
       
  1096 #endif
       
  1097 
       
  1098     // try to read data first (if it fails, the filedescriptor was closed)
       
  1099     const int basize = 4096;
       
  1100     QByteArray *ba = new QByteArray( basize );
       
  1101     n = ::read( fd, ba->data(), basize );
       
  1102     if ( n > 0 ) {
       
  1103 	ba->resize( n );
       
  1104 	buffer->append( ba );
       
  1105 	ba = 0;
       
  1106     } else {
       
  1107 	delete ba;
       
  1108 	ba = 0;
       
  1109     }
       
  1110     // eof or error?
       
  1111     if ( n == 0 || n == -1 ) {
       
  1112 	if ( fd == d->proc->socketStdout ) {
       
  1113 #if defined(QT_Q3PROCESS_DEBUG)
       
  1114 	    qDebug( "Q3Process::socketRead(): stdout (%d) closed", fd );
       
  1115 #endif
       
  1116 	    d->notifierStdout->setEnabled( false );
       
  1117 	    qDeleteInEventHandler(d->notifierStdout);
       
  1118 	    d->notifierStdout = 0;
       
  1119 	    qt_safe_close( d->proc->socketStdout );
       
  1120 	    d->proc->socketStdout = 0;
       
  1121 	    return;
       
  1122 	} else if ( fd == d->proc->socketStderr ) {
       
  1123 #if defined(QT_Q3PROCESS_DEBUG)
       
  1124 	    qDebug( "Q3Process::socketRead(): stderr (%d) closed", fd );
       
  1125 #endif
       
  1126 	    d->notifierStderr->setEnabled( false );
       
  1127 	    qDeleteInEventHandler(d->notifierStderr);
       
  1128 	    d->notifierStderr = 0;
       
  1129 	    qt_safe_close( d->proc->socketStderr );
       
  1130 	    d->proc->socketStderr = 0;
       
  1131 	    return;
       
  1132 	}
       
  1133     }
       
  1134 
       
  1135     if ( fd < FD_SETSIZE ) {
       
  1136 	fd_set fds;
       
  1137 	struct timeval tv;
       
  1138 	FD_ZERO( &fds );
       
  1139 	FD_SET( fd, &fds );
       
  1140 	tv.tv_sec = 0;
       
  1141 	tv.tv_usec = 0;
       
  1142 	while ( ::select( fd+1, &fds, 0, 0, &tv ) > 0 ) {
       
  1143 	    // prepare for the next round
       
  1144 	    FD_ZERO( &fds );
       
  1145 	    FD_SET( fd, &fds );
       
  1146 	    // read data
       
  1147 	    ba = new QByteArray( basize );
       
  1148 	    n = ::read( fd, ba->data(), basize );
       
  1149 	    if ( n > 0 ) {
       
  1150 		ba->resize( n );
       
  1151 		buffer->append( ba );
       
  1152 		ba = 0;
       
  1153 	    } else {
       
  1154 		delete ba;
       
  1155 		ba = 0;
       
  1156 		break;
       
  1157 	    }
       
  1158 	}
       
  1159     }
       
  1160 
       
  1161     d->socketReadCalled = true;
       
  1162     if ( fd == d->proc->socketStdout ) {
       
  1163 #if defined(QT_Q3PROCESS_DEBUG)
       
  1164 	qDebug( "Q3Process::socketRead(): %d bytes read from stdout (%d)",
       
  1165 		buffer->size()-oldSize, fd );
       
  1166 #endif
       
  1167 	emit readyReadStdout();
       
  1168     } else if ( fd == d->proc->socketStderr ) {
       
  1169 #if defined(QT_Q3PROCESS_DEBUG)
       
  1170 	qDebug( "Q3Process::socketRead(): %d bytes read from stderr (%d)",
       
  1171 		buffer->size()-oldSize, fd );
       
  1172 #endif
       
  1173 	emit readyReadStderr();
       
  1174     }
       
  1175     d->socketReadCalled = false;
       
  1176 }
       
  1177 
       
  1178 
       
  1179 /*
       
  1180   This private slot is called when the process tries to read data from standard
       
  1181   input.
       
  1182 */
       
  1183 void Q3Process::socketWrite( int fd )
       
  1184 {
       
  1185     while ( fd == d->proc->socketStdin && d->proc->socketStdin != 0 ) {
       
  1186 	if ( d->stdinBuf.isEmpty() ) {
       
  1187 	    d->notifierStdin->setEnabled( false );
       
  1188 	    return;
       
  1189 	}
       
  1190 	ssize_t ret = ::write( fd,
       
  1191 		d->stdinBuf.head()->data() + d->stdinBufRead,
       
  1192 		d->stdinBuf.head()->size() - d->stdinBufRead );
       
  1193 #if defined(QT_Q3PROCESS_DEBUG)
       
  1194 	qDebug( "Q3Process::socketWrite(): wrote %d bytes to stdin (%d)", ret, fd );
       
  1195 #endif
       
  1196 	if ( ret == -1 )
       
  1197 	    return;
       
  1198 	d->stdinBufRead += ret;
       
  1199 	if ( d->stdinBufRead == (ssize_t)d->stdinBuf.head()->size() ) {
       
  1200 	    d->stdinBufRead = 0;
       
  1201 	    delete d->stdinBuf.dequeue();
       
  1202 	    if ( wroteToStdinConnected && d->stdinBuf.isEmpty() )
       
  1203 		emit wroteToStdin();
       
  1204 	}
       
  1205     }
       
  1206 }
       
  1207 
       
  1208 /*!
       
  1209   \internal
       
  1210   Flushes standard input. This is useful if you want to use Q3Process in a
       
  1211   synchronous manner.
       
  1212 
       
  1213   This function should probably go into the public API.
       
  1214 */
       
  1215 void Q3Process::flushStdin()
       
  1216 {
       
  1217     if (d->proc)
       
  1218         socketWrite(d->proc->socketStdin);
       
  1219 }
       
  1220 
       
  1221 /*
       
  1222   This private slot is only used under Windows (but moc does not know about #if
       
  1223   defined()).
       
  1224 */
       
  1225 void Q3Process::timeout()
       
  1226 {
       
  1227 }
       
  1228 
       
  1229 
       
  1230 /*
       
  1231   This private function is used by connectNotify() and disconnectNotify() to
       
  1232   change the value of ioRedirection (and related behaviour)
       
  1233 */
       
  1234 void Q3Process::setIoRedirection( bool value )
       
  1235 {
       
  1236     ioRedirection = value;
       
  1237     if ( ioRedirection ) {
       
  1238 	if ( d->notifierStdout )
       
  1239 	    d->notifierStdout->setEnabled( true );
       
  1240 	if ( d->notifierStderr )
       
  1241 	    d->notifierStderr->setEnabled( true );
       
  1242     } else {
       
  1243 	if ( d->notifierStdout )
       
  1244 	    d->notifierStdout->setEnabled( false );
       
  1245 	if ( d->notifierStderr )
       
  1246 	    d->notifierStderr->setEnabled( false );
       
  1247     }
       
  1248 }
       
  1249 
       
  1250 /*
       
  1251   This private function is used by connectNotify() and
       
  1252   disconnectNotify() to change the value of notifyOnExit (and related
       
  1253   behaviour)
       
  1254 */
       
  1255 void Q3Process::setNotifyOnExit( bool value )
       
  1256 {
       
  1257     notifyOnExit = value;
       
  1258 }
       
  1259 
       
  1260 /*
       
  1261   This private function is used by connectNotify() and disconnectNotify() to
       
  1262   change the value of wroteToStdinConnected (and related behaviour)
       
  1263 */
       
  1264 void Q3Process::setWroteStdinConnected( bool value )
       
  1265 {
       
  1266     wroteToStdinConnected = value;
       
  1267 }
       
  1268 
       
  1269 /*!
       
  1270     \typedef Q3Process::PID
       
  1271     \internal
       
  1272 */
       
  1273 
       
  1274 Q3Process::PID Q3Process::processIdentifier()
       
  1275 {
       
  1276     if ( d->proc == 0 )
       
  1277 	return -1;
       
  1278     return d->proc->pid;
       
  1279 }
       
  1280 
       
  1281 QT_END_NAMESPACE
       
  1282 
       
  1283 #endif // QT_NO_PROCESS