summaryrefslogtreecommitdiff
path: root/core/launcher/qprocess_unix.cpp
Unidiff
Diffstat (limited to 'core/launcher/qprocess_unix.cpp') (more/less context) (show whitespace changes)
-rw-r--r--core/launcher/qprocess_unix.cpp1171
1 files changed, 1171 insertions, 0 deletions
diff --git a/core/launcher/qprocess_unix.cpp b/core/launcher/qprocess_unix.cpp
new file mode 100644
index 0000000..a07bf64
--- a/dev/null
+++ b/core/launcher/qprocess_unix.cpp
@@ -0,0 +1,1171 @@
1/**********************************************************************
2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3**
4** This file is part of the Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20
21//#include "qplatformdefs.h"
22
23// Solaris redefines connect -> __xnet_connect with _XOPEN_SOURCE_EXTENDED.
24#if defined(connect)
25#undef connect
26#endif
27
28#include "qprocess.h"
29
30#ifndef QT_NO_PROCESS
31
32#include "qapplication.h"
33#include "qqueue.h"
34#include "qlist.h"
35#include "qsocketnotifier.h"
36#include "qtimer.h"
37#include "qregexp.h"
38
39#include "qcleanuphandler_p.h"
40
41#include <stdlib.h>
42
43// ### FOR Qt 2.3 compat
44#include <unistd.h>
45#include <signal.h>
46#include <sys/socket.h>
47#include <sys/ioctl.h>
48#include <sys/wait.h>
49#include <sys/fcntl.h>
50
51#include <errno.h>
52
53#include <sys/resource.h>
54
55#ifdef __MIPSEL__
56# ifndef SOCK_DGRAM
57# define SOCK_DGRAM 1
58# endif
59# ifndef SOCK_STREAM
60# define SOCK_STREAM 2
61# endif
62#endif
63
64//#define QT_QPROCESS_DEBUG
65
66
67#ifdef Q_C_CALLBACKS
68extern "C" {
69#endif // Q_C_CALLBACKS
70
71#define QT_SIGNAL_RETTYPE void
72#define QT_SIGNAL_ARGS int
73#define QT_SIGNAL_IGNORE SIG_IGN
74
75 QT_SIGNAL_RETTYPE qt_C_sigchldHnd(QT_SIGNAL_ARGS);
76 QT_SIGNAL_RETTYPE qt_C_sigpipeHnd(QT_SIGNAL_ARGS);
77
78#ifdef Q_C_CALLBACKS
79}
80#endif // Q_C_CALLBACKS
81
82
83class QProc;
84class QProcessManager;
85class QProcessPrivate
86{
87public:
88 QProcessPrivate();
89 ~QProcessPrivate();
90
91 void closeOpenSocketsForChild();
92 void newProc( pid_t pid, QProcess *process );
93
94 QByteArray bufStdout;
95 QByteArray bufStderr;
96
97 QQueue<QByteArray> stdinBuf;
98
99 QSocketNotifier *notifierStdin;
100 QSocketNotifier *notifierStdout;
101 QSocketNotifier *notifierStderr;
102
103 ssize_t stdinBufRead;
104 QProc *proc;
105
106 bool exitValuesCalculated;
107 bool socketReadCalled;
108
109 static QProcessManager *procManager;
110};
111
112
113/***********************************************************************
114 *
115 * QProc
116 *
117 **********************************************************************/
118/*
119 The class QProcess does not necessarily map exactly to the running
120 child processes: if the process is finished, the QProcess class may still be
121 there; furthermore a user can use QProcess to start more than one process.
122
123 The helper-class QProc has the semantics that one instance of this class maps
124 directly to a running child process.
125*/
126class QProc
127{
128public:
129 QProc( pid_t p, QProcess *proc=0 ) : pid(p), process(proc)
130 {
131#if defined(QT_QPROCESS_DEBUG)
132 qDebug( "QProc: Constructor for pid %d and QProcess %p", pid, process );
133#endif
134 socketStdin = 0;
135 socketStdout = 0;
136 socketStderr = 0;
137 }
138 ~QProc()
139 {
140#if defined(QT_QPROCESS_DEBUG)
141 qDebug( "QProc: Destructor for pid %d and QProcess %p", pid, process );
142#endif
143 if ( process != 0 ) {
144 if ( process->d->notifierStdin )
145 process->d->notifierStdin->setEnabled( FALSE );
146 if ( process->d->notifierStdout )
147 process->d->notifierStdout->setEnabled( FALSE );
148 if ( process->d->notifierStderr )
149 process->d->notifierStderr->setEnabled( FALSE );
150 process->d->proc = 0;
151 }
152 if( socketStdin != 0 )
153 ::close( socketStdin );
154 // ### close these sockets even on parent exit or is it better only on
155 // sigchld (but what do I have to do with them on exit then)?
156 if( socketStdout != 0 )
157 ::close( socketStdout );
158 if( socketStderr != 0 )
159 ::close( socketStderr );
160 }
161
162 pid_t pid;
163 int socketStdin;
164 int socketStdout;
165 int socketStderr;
166 QProcess *process;
167};
168
169/***********************************************************************
170 *
171 * QProcessManager
172 *
173 **********************************************************************/
174class QProcessManager : public QObject
175{
176 Q_OBJECT
177
178public:
179 QProcessManager();
180 ~QProcessManager();
181
182 void append( QProc *p );
183 void remove( QProc *p );
184
185 void cleanup();
186
187public slots:
188 void removeMe();
189 void sigchldHnd( int );
190
191public:
192 struct sigaction oldactChld;
193 struct sigaction oldactPipe;
194 QList<QProc> *procList;
195 int sigchldFd[2];
196};
197
198QCleanupHandler<QProcessManager> qprocess_cleanup_procmanager;
199
200QProcessManager::QProcessManager()
201{
202 procList = new QList<QProc>;
203 procList->setAutoDelete( TRUE );
204
205 // The SIGCHLD handler writes to a socket to tell the manager that
206 // something happened. This is done to get the processing in sync with the
207 // event reporting.
208 if ( ::socketpair( AF_UNIX, SOCK_STREAM, 0, sigchldFd ) ) {
209 sigchldFd[0] = 0;
210 sigchldFd[1] = 0;
211 } else {
212#if defined(QT_QPROCESS_DEBUG)
213 qDebug( "QProcessManager: install socket notifier (%d)", sigchldFd[1] );
214#endif
215 QSocketNotifier *sn = new QSocketNotifier( sigchldFd[1],
216 QSocketNotifier::Read, this );
217 connect( sn, SIGNAL(activated(int)),
218 this, SLOT(sigchldHnd(int)) );
219 sn->setEnabled( TRUE );
220 }
221
222 // install a SIGCHLD handler and ignore SIGPIPE
223 struct sigaction act;
224
225#if defined(QT_QPROCESS_DEBUG)
226 qDebug( "QProcessManager: install a SIGCHLD handler" );
227#endif
228 act.sa_handler = qt_C_sigchldHnd;
229 sigemptyset( &(act.sa_mask) );
230 sigaddset( &(act.sa_mask), SIGCHLD );
231 act.sa_flags = SA_NOCLDSTOP;
232#if defined(SA_RESTART)
233 act.sa_flags |= SA_RESTART;
234#endif
235 if ( sigaction( SIGCHLD, &act, &oldactChld ) != 0 )
236 qWarning( "Error installing SIGCHLD handler" );
237
238#if defined(QT_QPROCESS_DEBUG)
239 qDebug( "QProcessManager: install a SIGPIPE handler (SIG_IGN)" );
240#endif
241 /*
242 Using qt_C_sigpipeHnd rather than SIG_IGN is a workaround
243 for a strange problem where GNU tar (called by backuprestore)
244 would hang on filesystem-full. Strangely, the qt_C_sigpipeHnd
245 is never even called, yet this avoids the hang.
246 */
247 act.sa_handler = qt_C_sigpipeHnd;
248 sigemptyset( &(act.sa_mask) );
249 sigaddset( &(act.sa_mask), SIGPIPE );
250 act.sa_flags = 0;
251 if ( sigaction( SIGPIPE, &act, &oldactPipe ) != 0 )
252 qWarning( "Error installing SIGPIPE handler" );
253}
254
255QProcessManager::~QProcessManager()
256{
257 delete procList;
258
259 if ( sigchldFd[0] != 0 )
260 ::close( sigchldFd[0] );
261 if ( sigchldFd[1] != 0 )
262 ::close( sigchldFd[1] );
263
264 // restore SIGCHLD handler
265#if defined(QT_QPROCESS_DEBUG)
266 qDebug( "QProcessManager: restore old sigchild handler" );
267#endif
268 if ( sigaction( SIGCHLD, &oldactChld, 0 ) != 0 )
269 qWarning( "Error restoring SIGCHLD handler" );
270
271#if defined(QT_QPROCESS_DEBUG)
272 qDebug( "QProcessManager: restore old sigpipe handler" );
273#endif
274 if ( sigaction( SIGPIPE, &oldactPipe, 0 ) != 0 )
275 qWarning( "Error restoring SIGPIPE handler" );
276}
277
278void QProcessManager::append( QProc *p )
279{
280 procList->append( p );
281#if defined(QT_QPROCESS_DEBUG)
282 qDebug( "QProcessManager: append process (procList.count(): %d)", procList->count() );
283#endif
284}
285
286void QProcessManager::remove( QProc *p )
287{
288 procList->remove( p );
289#if defined(QT_QPROCESS_DEBUG)
290 qDebug( "QProcessManager: remove process (procList.count(): %d)", procList->count() );
291#endif
292 cleanup();
293}
294
295void QProcessManager::cleanup()
296{
297 if ( procList->count() == 0 ) {
298 QTimer::singleShot( 0, this, SLOT(removeMe()) );
299 }
300}
301
302void QProcessManager::removeMe()
303{
304 if ( procList->count() == 0 ) {
305 qprocess_cleanup_procmanager.remove( &QProcessPrivate::procManager );
306 QProcessPrivate::procManager = 0;
307 delete this;
308 }
309}
310
311void QProcessManager::sigchldHnd( int fd )
312{
313 char tmp;
314 ::read( fd, &tmp, sizeof(tmp) );
315#if defined(QT_QPROCESS_DEBUG)
316 qDebug( "QProcessManager::sigchldHnd()" );
317#endif
318 QProc *proc;
319 QProcess *process;
320 bool removeProc;
321 proc = procList->first();
322 while ( proc != 0 ) {
323 removeProc = FALSE;
324 process = proc->process;
325 QProcess *process_exit_notify=0;
326 if ( process != 0 ) {
327 if ( !process->isRunning() ) {
328#if defined(QT_QPROCESS_DEBUG)
329 qDebug( "QProcessManager::sigchldHnd() (PID: %d): process exited (QProcess available)", proc->pid );
330#endif
331 // read pending data
332 int nbytes = 0;
333 if ( ::ioctl(proc->socketStdout, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) {
334#if defined(QT_QPROCESS_DEBUG)
335 qDebug( "QProcessManager::sigchldHnd() (PID: %d): reading %d bytes of pending data on stdout", proc->pid, nbytes );
336#endif
337 process->socketRead( proc->socketStdout );
338 }
339 nbytes = 0;
340 if ( ::ioctl(proc->socketStderr, 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 stderr", proc->pid, nbytes );
343#endif
344 process->socketRead( proc->socketStderr );
345 }
346
347 if ( process->notifyOnExit )
348 process_exit_notify = process;
349
350 removeProc = TRUE;
351 }
352 } else {
353 int status;
354 if ( ::waitpid( proc->pid, &status, WNOHANG ) == proc->pid ) {
355#if defined(QT_QPROCESS_DEBUG)
356 qDebug( "QProcessManager::sigchldHnd() (PID: %d): process exited (QProcess not available)", proc->pid );
357#endif
358 removeProc = TRUE;
359 }
360 }
361 if ( removeProc ) {
362 QProc *oldproc = proc;
363 proc = procList->next();
364 remove( oldproc );
365 } else {
366 proc = procList->next();
367 }
368 if ( process_exit_notify )
369 emit process_exit_notify->processExited();
370 }
371}
372
373#include "qprocess_unix.moc"
374
375
376/***********************************************************************
377 *
378 * QProcessPrivate
379 *
380 **********************************************************************/
381QProcessManager *QProcessPrivate::procManager = 0;
382
383QProcessPrivate::QProcessPrivate()
384{
385#if defined(QT_QPROCESS_DEBUG)
386 qDebug( "QProcessPrivate: Constructor" );
387#endif
388 stdinBufRead = 0;
389
390 notifierStdin = 0;
391 notifierStdout = 0;
392 notifierStderr = 0;
393
394 exitValuesCalculated = FALSE;
395 socketReadCalled = FALSE;
396
397 proc = 0;
398}
399
400QProcessPrivate::~QProcessPrivate()
401{
402#if defined(QT_QPROCESS_DEBUG)
403 qDebug( "QProcessPrivate: Destructor" );
404#endif
405
406 if ( proc != 0 ) {
407 if ( proc->socketStdin != 0 ) {
408 ::close( proc->socketStdin );
409 proc->socketStdin = 0;
410 }
411 proc->process = 0;
412 }
413
414 while ( !stdinBuf.isEmpty() ) {
415 delete stdinBuf.dequeue();
416 }
417 delete notifierStdin;
418 delete notifierStdout;
419 delete notifierStderr;
420}
421
422/*
423 Closes all open sockets in the child process that are not needed by the child
424 process. Otherwise one child may have an open socket on standard input, etc.
425 of another child.
426*/
427void QProcessPrivate::closeOpenSocketsForChild()
428{
429 if ( procManager != 0 ) {
430 if ( procManager->sigchldFd[0] != 0 )
431 ::close( procManager->sigchldFd[0] );
432 if ( procManager->sigchldFd[1] != 0 )
433 ::close( procManager->sigchldFd[1] );
434
435 // close also the sockets from other QProcess instances
436 QProc *proc;
437 for ( proc=procManager->procList->first(); proc!=0; proc=procManager->procList->next() ) {
438 ::close( proc->socketStdin );
439 ::close( proc->socketStdout );
440 ::close( proc->socketStderr );
441 }
442 }
443}
444
445void QProcessPrivate::newProc( pid_t pid, QProcess *process )
446{
447 proc = new QProc( pid, process );
448 if ( procManager == 0 ) {
449 procManager = new QProcessManager;
450 qprocess_cleanup_procmanager.add( &procManager );
451 }
452 // the QProcessManager takes care of deleting the QProc instances
453 procManager->append( proc );
454}
455
456/***********************************************************************
457 *
458 * sigchld handler callback
459 *
460 **********************************************************************/
461QT_SIGNAL_RETTYPE qt_C_sigchldHnd( QT_SIGNAL_ARGS )
462{
463 if ( QProcessPrivate::procManager == 0 )
464 return;
465 if ( QProcessPrivate::procManager->sigchldFd[0] == 0 )
466 return;
467
468 char a = 1;
469 ::write( QProcessPrivate::procManager->sigchldFd[0], &a, sizeof(a) );
470}
471QT_SIGNAL_RETTYPE qt_C_sigpipeHnd( QT_SIGNAL_ARGS )
472{
473 // Ignore (but in a way somehow different to SIG_IGN).
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
1157int QProcess::priority() const
1158{
1159 if ( d->proc )
1160 return getpriority(PRIO_PROCESS,d->proc->pid);
1161 return 0;
1162}
1163
1164void QProcess::setPriority(int p)
1165{
1166 if ( d->proc )
1167 setpriority(PRIO_PROCESS,d->proc->pid,p);
1168}
1169
1170
1171#endif // QT_NO_PROCESS