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