summaryrefslogtreecommitdiff
path: root/core/launcher/qprocess_unix.cpp
authorsandman <sandman>2002-12-17 19:16:18 (UTC)
committer sandman <sandman>2002-12-17 19:16:18 (UTC)
commitf36c70938c8c2907a1b61637af3bd589262b4b5e (patch) (unidiff)
tree7ed7429477ad0b17ea131fddcc5cab9fff088b26 /core/launcher/qprocess_unix.cpp
parentb6a03145553d7f536b04fc3355718cfdd72c590d (diff)
downloadopie-f36c70938c8c2907a1b61637af3bd589262b4b5e.zip
opie-f36c70938c8c2907a1b61637af3bd589262b4b5e.tar.gz
opie-f36c70938c8c2907a1b61637af3bd589262b4b5e.tar.bz2
replaced the private QProcess copy for the FTP server with the already
available libopie/OProcess
Diffstat (limited to 'core/launcher/qprocess_unix.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--core/launcher/qprocess_unix.cpp1158
1 files changed, 0 insertions, 1158 deletions
diff --git a/core/launcher/qprocess_unix.cpp b/core/launcher/qprocess_unix.cpp
deleted file mode 100644
index 75f0f0c..0000000
--- a/core/launcher/qprocess_unix.cpp
+++ b/dev/null
@@ -1,1158 +0,0 @@
1/****************************************************************************
2** $Id$
3**
4** Implementation of QProcess class for Unix
5**
6** Created : 20000905
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38//#include "qplatformdefs.h"
39
40// Solaris redefines connect -> __xnet_connect with _XOPEN_SOURCE_EXTENDED.
41#if defined(connect)
42#undef connect
43#endif
44
45#include "qprocess.h"
46
47#ifndef QT_NO_PROCESS
48
49#include "qapplication.h"
50#include "qqueue.h"
51#include "qlist.h"
52#include "qsocketnotifier.h"
53#include "qtimer.h"
54#include "qregexp.h"
55
56#include "qcleanuphandler_p.h"
57
58#include <stdlib.h>
59
60// ### FOR Qt 2.3 compat
61#include <unistd.h>
62#include <signal.h>
63#include <sys/socket.h>
64#include <sys/ioctl.h>
65#include <sys/wait.h>
66#include <sys/fcntl.h>
67
68#include <errno.h>
69
70#ifdef __MIPSEL__
71# ifndef SOCK_DGRAM
72# define SOCK_DGRAM 1
73# endif
74# ifndef SOCK_STREAM
75# define SOCK_STREAM 2
76# endif
77#endif
78
79//#define QT_QPROCESS_DEBUG
80
81
82#ifdef Q_C_CALLBACKS
83extern "C" {
84#endif // Q_C_CALLBACKS
85
86#define QT_SIGNAL_RETTYPE void
87#define QT_SIGNAL_ARGS int
88#define QT_SIGNAL_IGNORE SIG_IGN
89
90 QT_SIGNAL_RETTYPE qt_C_sigchldHnd(QT_SIGNAL_ARGS);
91
92#ifdef Q_C_CALLBACKS
93}
94#endif // Q_C_CALLBACKS
95
96
97class QProc;
98class QProcessManager;
99class QProcessPrivate
100{
101public:
102 QProcessPrivate();
103 ~QProcessPrivate();
104
105 void closeOpenSocketsForChild();
106 void newProc( pid_t pid, QProcess *process );
107
108 QByteArray bufStdout;
109 QByteArray bufStderr;
110
111 QQueue<QByteArray> stdinBuf;
112
113 QSocketNotifier *notifierStdin;
114 QSocketNotifier *notifierStdout;
115 QSocketNotifier *notifierStderr;
116
117 ssize_t stdinBufRead;
118 QProc *proc;
119
120 bool exitValuesCalculated;
121 bool socketReadCalled;
122
123 static QProcessManager *procManager;
124};
125
126
127/***********************************************************************
128 *
129 * QProc
130 *
131 **********************************************************************/
132/*
133 The class QProcess does not necessarily map exactly to the running
134 child processes: if the process is finished, the QProcess class may still be
135 there; furthermore a user can use QProcess to start more than one process.
136
137 The helper-class QProc has the semantics that one instance of this class maps
138 directly to a running child process.
139*/
140class QProc
141{
142public:
143 QProc( pid_t p, QProcess *proc=0 ) : pid(p), process(proc)
144 {
145#if defined(QT_QPROCESS_DEBUG)
146 qDebug( "QProc: Constructor for pid %d and QProcess %p", pid, process );
147#endif
148 socketStdin = 0;
149 socketStdout = 0;
150 socketStderr = 0;
151 }
152 ~QProc()
153 {
154#if defined(QT_QPROCESS_DEBUG)
155 qDebug( "QProc: Destructor for pid %d and QProcess %p", pid, process );
156#endif
157 if ( process != 0 ) {
158 if ( process->d->notifierStdin )
159 process->d->notifierStdin->setEnabled( FALSE );
160 if ( process->d->notifierStdout )
161 process->d->notifierStdout->setEnabled( FALSE );
162 if ( process->d->notifierStderr )
163 process->d->notifierStderr->setEnabled( FALSE );
164 process->d->proc = 0;
165 }
166 if( socketStdin != 0 )
167 ::close( socketStdin );
168 // ### close these sockets even on parent exit or is it better only on
169 // sigchld (but what do I have to do with them on exit then)?
170 if( socketStdout != 0 )
171 ::close( socketStdout );
172 if( socketStderr != 0 )
173 ::close( socketStderr );
174 }
175
176 pid_t pid;
177 int socketStdin;
178 int socketStdout;
179 int socketStderr;
180 QProcess *process;
181};
182
183/***********************************************************************
184 *
185 * QProcessManager
186 *
187 **********************************************************************/
188class QProcessManager : public QObject
189{
190 Q_OBJECT
191
192public:
193 QProcessManager();
194 ~QProcessManager();
195
196 void append( QProc *p );
197 void remove( QProc *p );
198
199 void cleanup();
200
201public slots:
202 void removeMe();
203 void sigchldHnd( int );
204
205public:
206 struct sigaction oldactChld;
207 struct sigaction oldactPipe;
208 QList<QProc> *procList;
209 int sigchldFd[2];
210};
211
212QCleanupHandler<QProcessManager> qprocess_cleanup_procmanager;
213
214QProcessManager::QProcessManager()
215{
216 procList = new QList<QProc>;
217 procList->setAutoDelete( TRUE );
218
219 // The SIGCHLD handler writes to a socket to tell the manager that
220 // something happened. This is done to get the processing in sync with the
221 // event reporting.
222 if ( ::socketpair( AF_UNIX, SOCK_STREAM, 0, sigchldFd ) ) {
223 sigchldFd[0] = 0;
224 sigchldFd[1] = 0;
225 } else {
226#if defined(QT_QPROCESS_DEBUG)
227 qDebug( "QProcessManager: install socket notifier (%d)", sigchldFd[1] );
228#endif
229 QSocketNotifier *sn = new QSocketNotifier( sigchldFd[1],
230 QSocketNotifier::Read, this );
231 connect( sn, SIGNAL(activated(int)),
232 this, SLOT(sigchldHnd(int)) );
233 sn->setEnabled( TRUE );
234 }
235
236 // install a SIGCHLD handler and ignore SIGPIPE
237 struct sigaction act;
238
239#if defined(QT_QPROCESS_DEBUG)
240 qDebug( "QProcessManager: install a SIGCHLD handler" );
241#endif
242 act.sa_handler = qt_C_sigchldHnd;
243 sigemptyset( &(act.sa_mask) );
244 sigaddset( &(act.sa_mask), SIGCHLD );
245 act.sa_flags = SA_NOCLDSTOP;
246#if defined(SA_RESTART)
247 act.sa_flags |= SA_RESTART;
248#endif
249 if ( sigaction( SIGCHLD, &act, &oldactChld ) != 0 )
250 qWarning( "Error installing SIGCHLD handler" );
251
252#if defined(QT_QPROCESS_DEBUG)
253 qDebug( "QProcessManager: install a SIGPIPE handler (SIG_IGN)" );
254#endif
255 act.sa_handler = QT_SIGNAL_IGNORE;
256 sigemptyset( &(act.sa_mask) );
257 sigaddset( &(act.sa_mask), SIGPIPE );
258 act.sa_flags = 0;
259 if ( sigaction( SIGPIPE, &act, &oldactPipe ) != 0 )
260 qWarning( "Error installing SIGPIPE handler" );
261}
262
263QProcessManager::~QProcessManager()
264{
265 delete procList;
266
267 if ( sigchldFd[0] != 0 )
268 ::close( sigchldFd[0] );
269 if ( sigchldFd[1] != 0 )
270 ::close( sigchldFd[1] );
271
272 // restore SIGCHLD handler
273#if defined(QT_QPROCESS_DEBUG)
274 qDebug( "QProcessManager: restore old sigchild handler" );
275#endif
276 if ( sigaction( SIGCHLD, &oldactChld, 0 ) != 0 )
277 qWarning( "Error restoring SIGCHLD handler" );
278
279#if defined(QT_QPROCESS_DEBUG)
280 qDebug( "QProcessManager: restore old sigpipe handler" );
281#endif
282 if ( sigaction( SIGPIPE, &oldactPipe, 0 ) != 0 )
283 qWarning( "Error restoring SIGPIPE handler" );
284}
285
286void QProcessManager::append( QProc *p )
287{
288 procList->append( p );
289#if defined(QT_QPROCESS_DEBUG)
290 qDebug( "QProcessManager: append process (procList.count(): %d)", procList->count() );
291#endif
292}
293
294void QProcessManager::remove( QProc *p )
295{
296 procList->remove( p );
297#if defined(QT_QPROCESS_DEBUG)
298 qDebug( "QProcessManager: remove process (procList.count(): %d)", procList->count() );
299#endif
300 cleanup();
301}
302
303void QProcessManager::cleanup()
304{
305 if ( procList->count() == 0 ) {
306 QTimer::singleShot( 0, this, SLOT(removeMe()) );
307 }
308}
309
310void QProcessManager::removeMe()
311{
312 if ( procList->count() == 0 ) {
313 qprocess_cleanup_procmanager.remove( &QProcessPrivate::procManager );
314 QProcessPrivate::procManager = 0;
315 delete this;
316 }
317}
318
319void QProcessManager::sigchldHnd( int fd )
320{
321 char tmp;
322 ::read( fd, &tmp, sizeof(tmp) );
323#if defined(QT_QPROCESS_DEBUG)
324 qDebug( "QProcessManager::sigchldHnd()" );
325#endif
326 QProc *proc;
327 QProcess *process;
328 bool removeProc;
329 proc = procList->first();
330 while ( proc != 0 ) {
331 removeProc = FALSE;
332 process = proc->process;
333 if ( process != 0 ) {
334 if ( !process->isRunning() ) {
335#if defined(QT_QPROCESS_DEBUG)
336 qDebug( "QProcessManager::sigchldHnd() (PID: %d): process exited (QProcess available)", proc->pid );
337#endif
338 // read pending data
339 int nbytes = 0;
340 if ( ::ioctl(proc->socketStdout, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) {
341#if defined(QT_QPROCESS_DEBUG)
342 qDebug( "QProcessManager::sigchldHnd() (PID: %d): reading %d bytes of pending data on stdout", proc->pid, nbytes );
343#endif
344 process->socketRead( proc->socketStdout );
345 }
346 nbytes = 0;
347 if ( ::ioctl(proc->socketStderr, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) {
348#if defined(QT_QPROCESS_DEBUG)
349 qDebug( "QProcessManager::sigchldHnd() (PID: %d): reading %d bytes of pending data on stderr", proc->pid, nbytes );
350#endif
351 process->socketRead( proc->socketStderr );
352 }
353
354 if ( process->notifyOnExit )
355 emit process->processExited();
356
357 removeProc = TRUE;
358 }
359 } else {
360 int status;
361 if ( ::waitpid( proc->pid, &status, WNOHANG ) == proc->pid ) {
362#if defined(QT_QPROCESS_DEBUG)
363 qDebug( "QProcessManager::sigchldHnd() (PID: %d): process exited (QProcess not available)", proc->pid );
364#endif
365 removeProc = TRUE;
366 }
367 }
368 if ( removeProc ) {
369 QProc *oldproc = proc;
370 proc = procList->next();
371 remove( oldproc );
372 } else {
373 proc = procList->next();
374 }
375 }
376}
377
378#include "qprocess_unix.moc"
379
380
381/***********************************************************************
382 *
383 * QProcessPrivate
384 *
385 **********************************************************************/
386QProcessManager *QProcessPrivate::procManager = 0;
387
388QProcessPrivate::QProcessPrivate()
389{
390#if defined(QT_QPROCESS_DEBUG)
391 qDebug( "QProcessPrivate: Constructor" );
392#endif
393 stdinBufRead = 0;
394
395 notifierStdin = 0;
396 notifierStdout = 0;
397 notifierStderr = 0;
398
399 exitValuesCalculated = FALSE;
400 socketReadCalled = FALSE;
401
402 proc = 0;
403}
404
405QProcessPrivate::~QProcessPrivate()
406{
407#if defined(QT_QPROCESS_DEBUG)
408 qDebug( "QProcessPrivate: Destructor" );
409#endif
410
411 if ( proc != 0 ) {
412 if ( proc->socketStdin != 0 ) {
413 ::close( proc->socketStdin );
414 proc->socketStdin = 0;
415 }
416 proc->process = 0;
417 }
418
419 while ( !stdinBuf.isEmpty() ) {
420 delete stdinBuf.dequeue();
421 }
422 delete notifierStdin;
423 delete notifierStdout;
424 delete notifierStderr;
425}
426
427/*
428 Closes all open sockets in the child process that are not needed by the child
429 process. Otherwise one child may have an open socket on standard input, etc.
430 of another child.
431*/
432void QProcessPrivate::closeOpenSocketsForChild()
433{
434 if ( procManager != 0 ) {
435 if ( procManager->sigchldFd[0] != 0 )
436 ::close( procManager->sigchldFd[0] );
437 if ( procManager->sigchldFd[1] != 0 )
438 ::close( procManager->sigchldFd[1] );
439
440 // close also the sockets from other QProcess instances
441 QProc *proc;
442 for ( proc=procManager->procList->first(); proc!=0; proc=procManager->procList->next() ) {
443 ::close( proc->socketStdin );
444 ::close( proc->socketStdout );
445 ::close( proc->socketStderr );
446 }
447 }
448}
449
450void QProcessPrivate::newProc( pid_t pid, QProcess *process )
451{
452 proc = new QProc( pid, process );
453 if ( procManager == 0 ) {
454 procManager = new QProcessManager;
455 qprocess_cleanup_procmanager.add( &procManager );
456 }
457 // the QProcessManager takes care of deleting the QProc instances
458 procManager->append( proc );
459}
460
461/***********************************************************************
462 *
463 * sigchld handler callback
464 *
465 **********************************************************************/
466QT_SIGNAL_RETTYPE qt_C_sigchldHnd( QT_SIGNAL_ARGS )
467{
468 if ( QProcessPrivate::procManager == 0 )
469 return;
470 if ( QProcessPrivate::procManager->sigchldFd[0] == 0 )
471 return;
472
473 char a = 1;
474 ::write( QProcessPrivate::procManager->sigchldFd[0], &a, sizeof(a) );
475}
476
477
478/***********************************************************************
479 *
480 * QProcess
481 *
482 **********************************************************************/
483/*!
484 This private class does basic initialization.
485*/
486void QProcess::init()
487{
488 d = new QProcessPrivate();
489 exitStat = 0;
490 exitNormal = FALSE;
491}
492
493/*!
494 This private class resets the process variables, etc. so that it can be used
495 for another process to start.
496*/
497void QProcess::reset()
498{
499 delete d;
500 d = new QProcessPrivate();
501 exitStat = 0;
502 exitNormal = FALSE;
503 d->bufStdout.resize( 0 );
504 d->bufStderr.resize( 0 );
505}
506
507QByteArray* QProcess::bufStdout()
508{
509 if ( d->proc && d->proc->socketStdout ) {
510 // ### can this cause a blocking behaviour (maybe do a ioctl() to see
511 // if data is available)?
512 socketRead( d->proc->socketStdout );
513 }
514 return &d->bufStdout;
515}
516
517QByteArray* QProcess::bufStderr()
518{
519 if ( d->proc && d->proc->socketStderr ) {
520 // ### can this cause a blocking behaviour (maybe do a ioctl() to see
521 // if data is available)?
522 socketRead( d->proc->socketStderr );
523 }
524 return &d->bufStderr;
525}
526
527void QProcess::consumeBufStdout( int consume )
528{
529 uint n = d->bufStdout.size();
530 if ( consume==-1 || (uint)consume >= n ) {
531 d->bufStdout.resize( 0 );
532 } else {
533 QByteArray tmp( n - consume );
534 memcpy( tmp.data(), d->bufStdout.data()+consume, n-consume );
535 d->bufStdout = tmp;
536 }
537}
538
539void QProcess::consumeBufStderr( int consume )
540{
541 uint n = d->bufStderr.size();
542 if ( consume==-1 || (uint)consume >= n ) {
543 d->bufStderr.resize( 0 );
544 } else {
545 QByteArray tmp( n - consume );
546 memcpy( tmp.data(), d->bufStderr.data()+consume, n-consume );
547 d->bufStderr = tmp;
548 }
549}
550
551/*!
552 Destroys the class.
553
554 If the process is running, it is NOT terminated! Standard input, standard
555 output and standard error of the process are closed.
556
557 You can connect the destroyed() signal to the kill() slot, if you want the
558 process to be terminated automatically when the class is destroyed.
559
560 \sa tryTerminate() kill()
561*/
562QProcess::~QProcess()
563{
564 delete d;
565}
566
567/*!
568 Tries to run a process for the command and arguments that were specified with
569 setArguments(), addArgument() or that were specified in the constructor. The
570 command is searched in the path for executable programs; you can also use an
571 absolute path to the command.
572
573 If \a env is null, then the process is started with the same environment as
574 the starting process. If \a env is non-null, then the values in the
575 stringlist are interpreted as environment setttings of the form \c
576 {key=value} and the process is started in these environment settings. For
577 convenience, there is a small exception to this rule: under Unix, if \a env
578 does not contain any settings for the environment variable \c
579 LD_LIBRARY_PATH, then this variable is inherited from the starting process;
580 under Windows the same applies for the enverionment varialbe \c PATH.
581
582 Returns TRUE if the process could be started, otherwise FALSE.
583
584 You can write data to standard input of the process with
585 writeToStdin(), you can close standard input with closeStdin() and you can
586 terminate the process tryTerminate() resp. kill().
587
588 You can call this function even when there already is a running
589 process in this object. In this case, QProcess closes standard input
590 of the old process and deletes pending data, i.e., you loose all
591 control over that process, but the process is not terminated. This applies
592 also if the process could not be started. (On operating systems that have
593 zombie processes, Qt will also wait() on the old process.)
594
595 \sa launch() closeStdin()
596*/
597bool QProcess::start( QStringList *env )
598{
599#if defined(QT_QPROCESS_DEBUG)
600 qDebug( "QProcess::start()" );
601#endif
602 reset();
603
604 int sStdin[2];
605 int sStdout[2];
606 int sStderr[2];
607
608 // open sockets for piping
609 if ( (comms & Stdin) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdin ) == -1 ) {
610 return FALSE;
611 }
612 if ( (comms & Stderr) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStderr ) == -1 ) {
613 return FALSE;
614 }
615 if ( (comms & Stdout) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdout ) == -1 ) {
616 return FALSE;
617 }
618
619 // the following pipe is only used to determine if the process could be
620 // started
621 int fd[2];
622 if ( pipe( fd ) < 0 ) {
623 // non critical error, go on
624 fd[0] = 0;
625 fd[1] = 0;
626 }
627
628 // construct the arguments for exec
629 QCString *arglistQ = new QCString[ _arguments.count() + 1 ];
630 const char** arglist = new const char*[ _arguments.count() + 1 ];
631 int i = 0;
632 for ( QStringList::Iterator it = _arguments.begin(); it != _arguments.end(); ++it ) {
633 arglistQ[i] = (*it).local8Bit();
634 arglist[i] = arglistQ[i];
635#if defined(QT_QPROCESS_DEBUG)
636 qDebug( "QProcess::start(): arg %d = %s", i, arglist[i] );
637#endif
638 i++;
639 }
640 arglist[i] = 0;
641
642 // Must make sure signal handlers are installed before exec'ing
643 // in case the process exits quickly.
644 if ( d->procManager == 0 ) {
645 d->procManager = new QProcessManager;
646 qprocess_cleanup_procmanager.add( &d->procManager );
647 }
648
649 // fork and exec
650 QApplication::flushX();
651 pid_t pid = fork();
652 if ( pid == 0 ) {
653 // child
654 d->closeOpenSocketsForChild();
655 if ( comms & Stdin ) {
656 ::close( sStdin[1] );
657 ::dup2( sStdin[0], STDIN_FILENO );
658 }
659 if ( comms & Stdout ) {
660 ::close( sStdout[0] );
661 ::dup2( sStdout[1], STDOUT_FILENO );
662 }
663 if ( comms & Stderr ) {
664 ::close( sStderr[0] );
665 ::dup2( sStderr[1], STDERR_FILENO );
666 }
667 if ( comms & DupStderr ) {
668 ::dup2( STDOUT_FILENO, STDERR_FILENO );
669 }
670#ifndef QT_NO_DIR
671 ::chdir( workingDir.absPath().latin1() );
672#endif
673 if ( fd[0] )
674 ::close( fd[0] );
675 if ( fd[1] )
676 ::fcntl( fd[1], F_SETFD, FD_CLOEXEC ); // close on exec shows sucess
677
678 if ( env == 0 ) { // inherit environment and start process
679 ::execvp( arglist[0], (char*const*)arglist ); // ### cast not nice
680 } else { // start process with environment settins as specified in env
681 // construct the environment for exec
682 int numEntries = env->count();
683 bool setLibraryPath =
684 env->grep( QRegExp( "^LD_LIBRARY_PATH=" ) ).isEmpty() &&
685 getenv( "LD_LIBRARY_PATH" ) != 0;
686 if ( setLibraryPath )
687 numEntries++;
688 QCString *envlistQ = new QCString[ numEntries + 1 ];
689 const char** envlist = new const char*[ numEntries + 1 ];
690 int i = 0;
691 if ( setLibraryPath ) {
692 envlistQ[i] = QString( "LD_LIBRARY_PATH=%1" ).arg( getenv( "LD_LIBRARY_PATH" ) ).local8Bit();
693 envlist[i] = envlistQ[i];
694 i++;
695 }
696 for ( QStringList::Iterator it = env->begin(); it != env->end(); ++it ) {
697 envlistQ[i] = (*it).local8Bit();
698 envlist[i] = envlistQ[i];
699 i++;
700 }
701 envlist[i] = 0;
702
703 // look for the executable in the search path
704 if ( _arguments.count()>0 && getenv("PATH")!=0 ) {
705 QString command = _arguments[0];
706 if ( !command.contains( '/' ) ) {
707 QStringList pathList = QStringList::split( ':', getenv( "PATH" ) );
708 for (QStringList::Iterator it = pathList.begin(); it != pathList.end(); ++it ) {
709 QString dir = *it;
710#ifdef Q_OS_MACX
711 if(QFile::exists(dir + "/" + command + ".app")) //look in a bundle
712 dir += "/" + command + ".app/Contents/MacOS";
713#endif
714#ifndef QT_NO_DIR
715 QFileInfo fileInfo( dir, command );
716#else
717 QFileInfo fileInfo( dir + "/" + command );
718#endif
719 if ( fileInfo.isExecutable() ) {
720 arglistQ[0] = fileInfo.filePath().local8Bit();
721 arglist[0] = arglistQ[0];
722 break;
723 }
724 }
725 }
726 }
727 ::execve( arglist[0], (char*const*)arglist, (char*const*)envlist ); // ### casts not nice
728 }
729 if ( fd[1] ) {
730 char buf = 0;
731 ::write( fd[1], &buf, 1 );
732 ::close( fd[1] );
733 }
734 ::exit( -1 );
735 } else if ( pid == -1 ) {
736 // error forking
737 goto error;
738 }
739
740 // test if exec was successful
741 if ( fd[1] )
742 ::close( fd[1] );
743 if ( fd[0] ) {
744 char buf;
745 for ( ;; ) {
746 int n = ::read( fd[0], &buf, 1 );
747 if ( n==1 ) {
748 // socket was not closed => error
749 d->proc = 0;
750 goto error;
751 } else if ( n==-1 ) {
752 if ( errno==EAGAIN || errno==EINTR )
753 // try it again
754 continue;
755 }
756 break;
757 }
758 ::close( fd[0] );
759 }
760
761 d->newProc( pid, this );
762
763 if ( comms & Stdin ) {
764 ::close( sStdin[0] );
765 d->proc->socketStdin = sStdin[1];
766 d->notifierStdin = new QSocketNotifier( sStdin[1], QSocketNotifier::Write );
767 connect( d->notifierStdin, SIGNAL(activated(int)),
768 this, SLOT(socketWrite(int)) );
769 // setup notifiers for the sockets
770 if ( !d->stdinBuf.isEmpty() ) {
771 d->notifierStdin->setEnabled( TRUE );
772 }
773 }
774 if ( comms & Stdout ) {
775 ::close( sStdout[1] );
776 d->proc->socketStdout = sStdout[0];
777 d->notifierStdout = new QSocketNotifier( sStdout[0], QSocketNotifier::Read );
778 connect( d->notifierStdout, SIGNAL(activated(int)),
779 this, SLOT(socketRead(int)) );
780 if ( ioRedirection )
781 d->notifierStdout->setEnabled( TRUE );
782 }
783 if ( comms & Stderr ) {
784 ::close( sStderr[1] );
785 d->proc->socketStderr = sStderr[0];
786 d->notifierStderr = new QSocketNotifier( sStderr[0], QSocketNotifier::Read );
787 connect( d->notifierStderr, SIGNAL(activated(int)),
788 this, SLOT(socketRead(int)) );
789 if ( ioRedirection )
790 d->notifierStderr->setEnabled( TRUE );
791 }
792
793 // cleanup and return
794 delete[] arglistQ;
795 delete[] arglist;
796 return TRUE;
797
798error:
799#if defined(QT_QPROCESS_DEBUG)
800 qDebug( "QProcess::start(): error starting process" );
801#endif
802 if ( d->procManager )
803 d->procManager->cleanup();
804 if ( comms & Stdin ) {
805 ::close( sStdin[1] );
806 ::close( sStdin[0] );
807 }
808 if ( comms & Stdout ) {
809 ::close( sStdout[0] );
810 ::close( sStdout[1] );
811 }
812 if ( comms & Stderr ) {
813 ::close( sStderr[0] );
814 ::close( sStderr[1] );
815 }
816 ::close( fd[0] );
817 ::close( fd[1] );
818 delete[] arglistQ;
819 delete[] arglist;
820 return FALSE;
821}
822
823
824/*!
825 Asks the process to terminate. Processes can ignore this wish. If you want to
826 be sure that the process really terminates, you must use kill() instead.
827
828 The slot returns immediately: it does not wait until the process has
829 finished. When the process really exited, the signal processExited() is
830 emitted.
831
832 \sa kill() processExited()
833*/
834void QProcess::tryTerminate() const
835{
836 if ( d->proc != 0 )
837 ::kill( d->proc->pid, SIGTERM );
838}
839
840/*!
841 Terminates the process. This is not a safe way to end a process since the
842 process will not be able to do cleanup. tryTerminate() is a safer way to do
843 it, but processes might ignore a tryTerminate().
844
845 The nice way to end a process and to be sure that it is finished, is doing
846 something like this:
847 \code
848 process->tryTerminate();
849 QTimer::singleShot( 5000, process, SLOT( kill() ) );
850 \endcode
851
852 This tries to terminate the process the nice way. If the process is still
853 running after 5 seconds, it terminates the process the hard way. The timeout
854 should be chosen depending on the time the process needs to do all the
855 cleanup: use a higher value if the process is likely to do heavy computation
856 on cleanup.
857
858 The slot returns immediately: it does not wait until the process has
859 finished. When the process really exited, the signal processExited() is
860 emitted.
861
862 \sa tryTerminate() processExited()
863*/
864void QProcess::kill() const
865{
866 if ( d->proc != 0 )
867 ::kill( d->proc->pid, SIGKILL );
868}
869
870/*!
871 Returns TRUE if the process is running, otherwise FALSE.
872
873 \sa normalExit() exitStatus() processExited()
874*/
875bool QProcess::isRunning() const
876{
877 if ( d->exitValuesCalculated ) {
878#if defined(QT_QPROCESS_DEBUG)
879 qDebug( "QProcess::isRunning(): FALSE (already computed)" );
880#endif
881 return FALSE;
882 }
883 if ( d->proc == 0 )
884 return FALSE;
885 int status;
886 if ( ::waitpid( d->proc->pid, &status, WNOHANG ) == d->proc->pid )
887 {
888 // compute the exit values
889 QProcess *that = (QProcess*)this; // mutable
890 that->exitNormal = WIFEXITED( status ) != 0;
891 if ( exitNormal ) {
892 that->exitStat = (char)WEXITSTATUS( status );
893 }
894 d->exitValuesCalculated = TRUE;
895#if defined(QT_QPROCESS_DEBUG)
896 qDebug( "QProcess::isRunning() (PID: %d): FALSE", d->proc->pid );
897#endif
898 return FALSE;
899 }
900#if defined(QT_QPROCESS_DEBUG)
901 qDebug( "QProcess::isRunning() (PID: %d): TRUE", d->proc->pid );
902#endif
903 return TRUE;
904}
905
906/*!
907 Writes the data \a buf to the standard input of the process. The process may
908 or may not read this data.
909
910 This function returns immediately; the QProcess class might write the data at
911 a later point (you have to enter the event loop for that). When all the data
912 is written to the process, the signal wroteToStdin() is emitted. This does
913 not mean that the process really read the data, since this class only detects
914 when it was able to write the data to the operating system.
915
916 \sa wroteToStdin() closeStdin() readStdout() readStderr()
917*/
918void QProcess::writeToStdin( const QByteArray& buf )
919{
920#if defined(QT_QPROCESS_DEBUG)
921// qDebug( "QProcess::writeToStdin(): write to stdin (%d)", d->socketStdin );
922#endif
923 d->stdinBuf.enqueue( new QByteArray(buf) );
924 if ( d->notifierStdin != 0 )
925 d->notifierStdin->setEnabled( TRUE );
926}
927
928
929/*!
930 Closes standard input of the process.
931
932 This function also deletes pending data that is not written to standard input
933 yet.
934
935 \sa wroteToStdin()
936*/
937void QProcess::closeStdin()
938{
939 if ( d->proc == 0 )
940 return;
941 if ( d->proc->socketStdin !=0 ) {
942 while ( !d->stdinBuf.isEmpty() ) {
943 delete d->stdinBuf.dequeue();
944 }
945 delete d->notifierStdin;
946 d->notifierStdin = 0;
947 if ( ::close( d->proc->socketStdin ) != 0 ) {
948 qWarning( "Could not close stdin of child process" );
949 }
950#if defined(QT_QPROCESS_DEBUG)
951 qDebug( "QProcess::closeStdin(): stdin (%d) closed", d->proc->socketStdin );
952#endif
953 d->proc->socketStdin = 0;
954 }
955}
956
957
958/*
959 This private slot is called when the process has outputted data to either
960 standard output or standard error.
961*/
962void QProcess::socketRead( int fd )
963{
964 if ( d->socketReadCalled ) {
965 // the slots that are connected to the readyRead...() signals might
966 // trigger a recursive call of socketRead(). Avoid this since you get a
967 // blocking read otherwise.
968 return;
969 }
970#if defined(QT_QPROCESS_DEBUG)
971 qDebug( "QProcess::socketRead(): %d", fd );
972#endif
973 if ( fd == 0 )
974 return;
975 const int bufsize = 4096;
976 QByteArray *buffer = 0;
977 uint oldSize;
978 int n;
979 if ( fd == d->proc->socketStdout ) {
980 buffer = &d->bufStdout;
981 } else if ( fd == d->proc->socketStderr ) {
982 buffer = &d->bufStderr;
983 } else {
984 // this case should never happen, but just to be safe
985 return;
986 }
987
988 // read data
989 oldSize = buffer->size();
990 buffer->resize( oldSize + bufsize );
991 n = ::read( fd, buffer->data()+oldSize, bufsize );
992 if ( n > 0 )
993 buffer->resize( oldSize + n );
994 else
995 buffer->resize( oldSize );
996 // eof or error?
997 if ( n == 0 || n == -1 ) {
998 if ( fd == d->proc->socketStdout ) {
999#if defined(QT_QPROCESS_DEBUG)
1000 qDebug( "QProcess::socketRead(): stdout (%d) closed", fd );
1001#endif
1002 d->notifierStdout->setEnabled( FALSE );
1003 delete d->notifierStdout;
1004 d->notifierStdout = 0;
1005 ::close( d->proc->socketStdout );
1006 d->proc->socketStdout = 0;
1007 return;
1008 } else if ( fd == d->proc->socketStderr ) {
1009#if defined(QT_QPROCESS_DEBUG)
1010 qDebug( "QProcess::socketRead(): stderr (%d) closed", fd );
1011#endif
1012 d->notifierStderr->setEnabled( FALSE );
1013 delete d->notifierStderr;
1014 d->notifierStderr = 0;
1015 ::close( d->proc->socketStderr );
1016 d->proc->socketStderr = 0;
1017 return;
1018 }
1019 }
1020 // read all data that is available
1021 while ( n == bufsize ) {
1022 oldSize = buffer->size();
1023 buffer->resize( oldSize + bufsize );
1024 n = ::read( fd, buffer->data()+oldSize, bufsize );
1025 if ( n > 0 )
1026 buffer->resize( oldSize + n );
1027 else
1028 buffer->resize( oldSize );
1029 }
1030
1031 d->socketReadCalled = TRUE;
1032 if ( fd == d->proc->socketStdout ) {
1033#if defined(QT_QPROCESS_DEBUG)
1034 qDebug( "QProcess::socketRead(): %d bytes read from stdout (%d)",
1035 buffer->size()-oldSize, fd );
1036#endif
1037 emit readyReadStdout();
1038 } else if ( fd == d->proc->socketStderr ) {
1039#if defined(QT_QPROCESS_DEBUG)
1040 qDebug( "QProcess::socketRead(): %d bytes read from stderr (%d)",
1041 buffer->size()-oldSize, fd );
1042#endif
1043 emit readyReadStderr();
1044 }
1045 d->socketReadCalled = FALSE;
1046}
1047
1048
1049/*
1050 This private slot is called when the process tries to read data from standard
1051 input.
1052*/
1053void QProcess::socketWrite( int fd )
1054{
1055 if ( fd != d->proc->socketStdin || d->proc->socketStdin == 0 )
1056 return;
1057 if ( d->stdinBuf.isEmpty() ) {
1058 d->notifierStdin->setEnabled( FALSE );
1059 return;
1060 }
1061#if defined(QT_QPROCESS_DEBUG)
1062 qDebug( "QProcess::socketWrite(): write to stdin (%d)", fd );
1063#endif
1064 ssize_t ret = ::write( fd,
1065 d->stdinBuf.head()->data() + d->stdinBufRead,
1066 d->stdinBuf.head()->size() - d->stdinBufRead );
1067 if ( ret > 0 )
1068 d->stdinBufRead += ret;
1069 if ( d->stdinBufRead == (ssize_t)d->stdinBuf.head()->size() ) {
1070 d->stdinBufRead = 0;
1071 delete d->stdinBuf.dequeue();
1072 if ( wroteToStdinConnected && d->stdinBuf.isEmpty() )
1073 emit wroteToStdin();
1074 socketWrite( fd );
1075 }
1076}
1077
1078/*!
1079 \internal
1080 Flushes standard input. This is useful if you want to use QProcess in a
1081 synchronous manner.
1082
1083 This function should probably go into the public API.
1084*/
1085void QProcess::flushStdin()
1086{
1087 socketWrite( d->proc->socketStdin );
1088}
1089
1090/*
1091 This private slot is only used under Windows (but moc does not know about #if
1092 defined()).
1093*/
1094void QProcess::timeout()
1095{
1096}
1097
1098
1099/*
1100 This private function is used by connectNotify() and disconnectNotify() to
1101 change the value of ioRedirection (and related behaviour)
1102*/
1103void QProcess::setIoRedirection( bool value )
1104{
1105 ioRedirection = value;
1106 if ( ioRedirection ) {
1107 if ( d->notifierStdout )
1108 d->notifierStdout->setEnabled( TRUE );
1109 if ( d->notifierStderr )
1110 d->notifierStderr->setEnabled( TRUE );
1111 } else {
1112 if ( d->notifierStdout )
1113 d->notifierStdout->setEnabled( FALSE );
1114 if ( d->notifierStderr )
1115 d->notifierStderr->setEnabled( FALSE );
1116 }
1117}
1118
1119/*
1120 This private function is used by connectNotify() and
1121 disconnectNotify() to change the value of notifyOnExit (and related
1122 behaviour)
1123*/
1124void QProcess::setNotifyOnExit( bool value )
1125{
1126 notifyOnExit = value;
1127}
1128
1129/*
1130 This private function is used by connectNotify() and disconnectNotify() to
1131 change the value of wroteToStdinConnected (and related behaviour)
1132*/
1133void QProcess::setWroteStdinConnected( bool value )
1134{
1135 wroteToStdinConnected = value;
1136}
1137
1138/*! \enum QProcess::PID
1139 \internal
1140*/
1141/*!
1142 Returns platform dependent information about the process. This can be used
1143 together with platform specific system calls.
1144
1145 Under Unix the return value is the PID of the process, or -1 if no process is
1146 belonging to this object.
1147
1148 Under Windows it is a pointer to the \c PROCESS_INFORMATION struct, or 0 if
1149 no process is belonging to this object.
1150*/
1151QProcess::PID QProcess::processIdentifier()
1152{
1153 if ( d->proc == 0 )
1154 return -1;
1155 return d->proc->pid;
1156}
1157
1158#endif // QT_NO_PROCESS