summaryrefslogtreecommitdiff
authorzecke <zecke>2003-08-31 20:25:29 (UTC)
committer zecke <zecke>2003-08-31 20:25:29 (UTC)
commit143807c9d438ee6f07e92e6009ec5633088c34f4 (patch) (unidiff)
tree85c8878e27e90f1b12d76994add8b530f07dc321
parent2fb39071c9880b462acd6fa7314d99a032a9df47 (diff)
downloadopie-143807c9d438ee6f07e92e6009ec5633088c34f4.zip
opie-143807c9d438ee6f07e92e6009ec5633088c34f4.tar.gz
opie-143807c9d438ee6f07e92e6009ec5633088c34f4.tar.bz2
mickeyl again ;)
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--core/launcher/qprocess.cpp639
-rw-r--r--core/launcher/qprocess.h163
-rw-r--r--core/launcher/qprocess_unix.cpp1171
3 files changed, 1973 insertions, 0 deletions
diff --git a/core/launcher/qprocess.cpp b/core/launcher/qprocess.cpp
new file mode 100644
index 0000000..97bd539
--- a/dev/null
+++ b/core/launcher/qprocess.cpp
@@ -0,0 +1,639 @@
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 <stdio.h>
22#include <stdlib.h>
23
24#include "qprocess.h"
25
26#ifndef QT_NO_PROCESS
27
28#include "qapplication.h"
29
30
31//#define QT_QPROCESS_DEBUG
32
33
34/*!
35 \class QProcess qprocess.h
36
37 \brief The QProcess class is used to start external programs and to
38 communicate with them.
39
40 This is a temporary class. This will be replaced by Qt 3's QProcess class.
41
42 \ingroup qtopiaemb
43*/
44
45/*!
46 \enum QProcess::Communication
47
48 This enum type defines the communication channels connected to the
49 process.
50
51 \value Stdin Data can be written to the process's standard input.
52
53 \value Stdout Data can be read from the process's standard output.
54
55 \value Stderr Data can be read from the process's standard error.
56
57 \value DupStderr Duplicates standard error to standard output for new
58 processes; i.e. everything that the process writes to standard error, is
59 reported by QProcess on standard output instead. This is especially useful if
60 your application requires that the output on standard output and standard
61 error is read in the same order as the process output it. Please note that
62 this is a binary flag, so if you want to activate this together with standard
63 input, output and error redirection (the default), you have to specify
64 \c{Stdin|Stdout|Stderr|DupStderr} for the setCommunication() call.
65
66 \sa setCommunication() communication()
67*/
68
69/*!
70 Constructs a QProcess object. The \a parent and \a name parameters are passed
71 to the QObject constructor.
72
73 \sa setArguments() addArgument() start()
74*/
75QProcess::QProcess( QObject *parent, const char *name )
76 : QObject( parent, name ), ioRedirection( FALSE ), notifyOnExit( FALSE ),
77 wroteToStdinConnected( FALSE ),
78 readStdoutCalled( FALSE ), readStderrCalled( FALSE ),
79 comms( Stdin|Stdout|Stderr )
80{
81 init();
82}
83
84/*!
85 Constructs a QProcess with \a arg0 as the command to be executed. The
86 \a parent and \a name parameters are passed to the QObject constructor.
87
88 The process is not started. You must call start() or launch()
89 to start the process.
90
91 \sa setArguments() addArgument() start()
92*/
93QProcess::QProcess( const QString& arg0, QObject *parent, const char *name )
94 : QObject( parent, name ), ioRedirection( FALSE ), notifyOnExit( FALSE ),
95 wroteToStdinConnected( FALSE ),
96 readStdoutCalled( FALSE ), readStderrCalled( FALSE ),
97 comms( Stdin|Stdout|Stderr )
98{
99 init();
100 addArgument( arg0 );
101}
102
103/*!
104 Constructs a QProcess with \a args as the arguments of the process. The first
105 element in the list is the command to be executed. The other elements in the
106 list are the arguments to this command. The \a parent and \a name
107 parameters are passed to the QObject constructor.
108
109 The process is not started. You must call start() or launch()
110 to start the process.
111
112 \sa setArguments() addArgument() start()
113*/
114QProcess::QProcess( const QStringList& args, QObject *parent, const char *name )
115 : QObject( parent, name ), ioRedirection( FALSE ), notifyOnExit( FALSE ),
116 wroteToStdinConnected( FALSE ),
117 readStdoutCalled( FALSE ), readStderrCalled( FALSE ),
118 comms( Stdin|Stdout|Stderr )
119{
120 init();
121 setArguments( args );
122}
123
124
125/*!
126 Returns the list of arguments that are set for the process. Arguments can be
127 specified with the constructor or with the functions setArguments() and
128 addArgument().
129
130 \sa setArguments() addArgument()
131*/
132QStringList QProcess::arguments() const
133{
134 return _arguments;
135}
136
137/*!
138 Clears the list of arguments that are set for the process.
139
140 \sa setArguments() addArgument()
141*/
142void QProcess::clearArguments()
143{
144 _arguments.clear();
145}
146
147/*!
148 Sets \a args as the arguments for the process. The first element in the list
149 is the command to be executed. The other elements in the list are the
150 arguments to the command. Any previous arguments are deleted.
151
152 \sa arguments() addArgument()
153*/
154void QProcess::setArguments( const QStringList& args )
155{
156 _arguments = args;
157}
158
159/*!
160 Adds \a arg to the end of the list of arguments.
161
162 The first element in the list of arguments is the command to be
163 executed; the following elements are the arguments to the command.
164
165 \sa arguments() setArguments()
166*/
167void QProcess::addArgument( const QString& arg )
168{
169 _arguments.append( arg );
170}
171
172#ifndef QT_NO_DIR
173/*!
174 Returns the working directory that was set with
175 setWorkingDirectory(), or the current directory if none has been
176 set.
177
178 \sa setWorkingDirectory() QDir::current()
179*/
180QDir QProcess::workingDirectory() const
181{
182 return workingDir;
183}
184
185/*!
186 Sets \a dir as the working directory for a process. This does not affect
187 running processes; only processes that are started afterwards are affected.
188
189 Setting the working directory is especially useful for processes that try to
190 access files with relative filenames.
191
192 \sa workingDirectory() start()
193*/
194void QProcess::setWorkingDirectory( const QDir& dir )
195{
196 workingDir = dir;
197}
198#endif //QT_NO_DIR
199
200/*!
201 Returns the communication required with the process.
202
203 \sa setCommunication()
204*/
205int QProcess::communication() const
206{
207 return comms;
208}
209
210/*!
211 Sets \a commFlags as the communication required with the process.
212
213 \a commFlags is a bitwise OR between the flags defined in \c Communication.
214
215 The default is \c{Stdin|Stdout|Stderr}.
216
217 \sa communication()
218*/
219void QProcess::setCommunication( int commFlags )
220{
221 comms = commFlags;
222}
223
224/*!
225 Returns TRUE if the process has exited normally; otherwise returns
226 FALSE. This implies that this function returns FALSE if the process
227 is still running.
228
229 \sa isRunning() exitStatus() processExited()
230*/
231bool QProcess::normalExit() const
232{
233 // isRunning() has the side effect that it determines the exit status!
234 if ( isRunning() )
235 return FALSE;
236 else
237 return exitNormal;
238}
239
240/*!
241 Returns the exit status of the process or 0 if the process is still
242 running. This function returns immediately and does not wait until
243 the process is finished.
244
245 If normalExit() is FALSE (e.g. if the program was killed or
246 crashed), this function returns 0, so you should check the return
247 value of normalExit() before relying on this value.
248
249 \sa normalExit() processExited()
250*/
251int QProcess::exitStatus() const
252{
253 // isRunning() has the side effect that it determines the exit status!
254 if ( isRunning() )
255 return 0;
256 else
257 return exitStat;
258}
259
260
261/*!
262 Reads the data that the process has written to standard output. When
263 new data is written to standard output, the class emits the signal
264 readyReadStdout().
265
266 If there is no data to read, this function returns a QByteArray of
267 size 0: it does not wait until there is something to read.
268
269 \sa readyReadStdout() readLineStdout() readStderr() writeToStdin()
270*/
271QByteArray QProcess::readStdout()
272{
273 if ( readStdoutCalled ) {
274 return QByteArray();
275 }
276 readStdoutCalled = TRUE;
277
278 QByteArray buf = bufStdout()->copy();
279 consumeBufStdout( -1 ); // consume everything
280
281 readStdoutCalled = FALSE;
282 return buf;
283}
284
285/*!
286 Reads the data that the process has written to standard error. When
287 new data is written to standard error, the class emits the signal
288 readyReadStderr().
289
290 If there is no data to read, this function returns a QByteArray of
291 size 0: it does not wait until there is something to read.
292
293 \sa readyReadStderr() readLineStderr() readStdout() writeToStdin()
294*/
295QByteArray QProcess::readStderr()
296{
297 if ( readStderrCalled ) {
298 return QByteArray();
299 }
300 readStderrCalled = TRUE;
301
302 QByteArray buf = bufStderr()->copy();
303 consumeBufStderr( -1 ); // consume everything
304
305 readStderrCalled = FALSE;
306 return buf;
307}
308
309/*!
310 Returns TRUE if it's possible to read an entire line of text from
311 standard output at this time; otherwise returns FALSE.
312
313 \sa readLineStdout() canReadLineStderr()
314*/
315bool QProcess::canReadLineStdout() const
316{
317 QProcess *that = (QProcess*)this;
318 return that->scanNewline( TRUE, 0 );
319}
320
321/*!
322 Returns TRUE if it's possible to read an entire line of text from
323 standard error at this time; otherwise returns FALSE.
324
325 \sa readLineStderr() canReadLineStdout()
326*/
327bool QProcess::canReadLineStderr() const
328{
329 QProcess *that = (QProcess*)this;
330 return that->scanNewline( FALSE, 0 );
331}
332
333/*!
334 Reads a line of text from standard output, excluding any trailing newline or
335 carriage return characters, and returns it. Returns QString::null if
336 canReadLineStdout() returns FALSE.
337
338 \sa canReadLineStdout() readyReadStdout() readStdout() readLineStderr()
339*/
340QString QProcess::readLineStdout()
341{
342 QByteArray a;
343 QString s;
344 if ( scanNewline( TRUE, &a ) ) {
345 if ( a.isEmpty() )
346 s = "";
347 else
348 s = QString( a );
349 }
350 return s;
351}
352
353/*!
354 Reads a line of text from standard error, excluding any trailing newline or
355 carriage return characters and returns it. Returns QString::null if
356 canReadLineStderr() returns FALSE.
357
358 \sa canReadLineStderr() readyReadStderr() readStderr() readLineStdout()
359*/
360QString QProcess::readLineStderr()
361{
362 QByteArray a;
363 QString s;
364 if ( scanNewline( FALSE, &a ) ) {
365 if ( a.isEmpty() )
366 s = "";
367 else
368 s = QString( a );
369 }
370 return s;
371}
372
373/*!
374 This private function scans for any occurrence of \n or \r\n in the
375 buffer \e buf. It stores the text in the byte array \a store if it is
376 non-null.
377*/
378bool QProcess::scanNewline( bool stdOut, QByteArray *store )
379{
380 QByteArray *buf;
381 if ( stdOut )
382 buf = bufStdout();
383 else
384 buf = bufStderr();
385 uint n = buf->size();
386 uint i;
387 for ( i=0; i<n; i++ ) {
388 if ( buf->at(i) == '\n' ) {
389 break;
390 }
391 }
392 if ( i >= n )
393 return FALSE;
394
395 if ( store ) {
396 uint lineLength = i;
397 if ( lineLength>0 && buf->at(lineLength-1) == '\r' )
398 lineLength--; // (if there are two \r, let one stay)
399 store->resize( lineLength );
400 memcpy( store->data(), buf->data(), lineLength );
401 if ( stdOut )
402 consumeBufStdout( i+1 );
403 else
404 consumeBufStderr( i+1 );
405 }
406 return TRUE;
407}
408
409/*!
410 \fn void QProcess::launchFinished()
411
412 This signal is emitted when the process was started with launch().
413 If the start was successful, this signal is emitted after all the
414 data has been written to standard input. If the start failed, then
415 this signal is emitted immediately.
416
417 \sa launch() QObject::deleteLater()
418*/
419
420/*!
421 Runs the process and writes the data \a buf to the process's standard input.
422 If all the data is written to standard input, standard input is
423 closed. The command is searched for in the path for executable programs;
424 you can also use an absolute path in the command itself.
425
426 If \a env is null, then the process is started with the same environment as
427 the starting process. If \a env is non-null, then the values in the
428 stringlist are interpreted as environment setttings of the form \c
429 {key=value} and the process is started with these environment settings. For
430 convenience, there is a small exception to this rule under Unix: if \a env
431 does not contain any settings for the environment variable \c
432 LD_LIBRARY_PATH, then this variable is inherited from the starting process.
433
434 Returns TRUE if the process could be started; otherwise returns FALSE.
435
436 Note that you should not use the slots writeToStdin() and closeStdin() on
437 processes started with launch(), since the result is not well-defined. If you
438 need these slots, use start() instead.
439
440 The process may or may not read the \a buf data sent to its standard
441 input.
442
443 You can call this function even when a process that was started with
444 this instance is still running. Be aware that if you do this the
445 standard input of the process that was launched first will be
446 closed, with any pending data being deleted, and the process will be
447 left to run out of your control. Similarly, if the process could not
448 be started the standard input will be closed and the pending data
449 deleted. (On operating systems that have zombie processes, Qt will
450 also wait() on the old process.)
451
452 The object emits the signal launchFinished() when this function
453 call is finished. If the start was successful, this signal is
454 emitted after all the data has been written to standard input. If
455 the start failed, then this signal is emitted immediately.
456
457 \sa start() launchFinished();
458*/
459bool QProcess::launch( const QByteArray& buf, QStringList *env )
460{
461 if ( start( env ) ) {
462 if ( !buf.isEmpty() ) {
463 connect( this, SIGNAL(wroteToStdin()),
464 this, SLOT(closeStdinLaunch()) );
465 writeToStdin( buf );
466 } else {
467 closeStdin();
468 emit launchFinished();
469 }
470 return TRUE;
471 } else {
472 emit launchFinished();
473 return FALSE;
474 }
475}
476
477/*! \overload
478
479 The data \a buf is written to standard input with writeToStdin()
480 using the QString::local8Bit() representation of the strings.
481*/
482bool QProcess::launch( const QString& buf, QStringList *env )
483{
484 if ( start( env ) ) {
485 if ( !buf.isEmpty() ) {
486 connect( this, SIGNAL(wroteToStdin()),
487 this, SLOT(closeStdinLaunch()) );
488 writeToStdin( buf );
489 } else {
490 closeStdin();
491 emit launchFinished();
492 }
493 return TRUE;
494 } else {
495 emit launchFinished();
496 return FALSE;
497 }
498}
499
500/*!
501 This private slot is used by the launch() functions to close standard input.
502*/
503void QProcess::closeStdinLaunch()
504{
505 disconnect( this, SIGNAL(wroteToStdin()),
506 this, SLOT(closeStdinLaunch()) );
507 closeStdin();
508 emit launchFinished();
509}
510
511
512/*!
513 \fn void QProcess::readyReadStdout()
514
515 This signal is emitted when the process has written data to standard output.
516 You can read the data with readStdout().
517
518 Note that this signal is only emitted when there is new data and not
519 when there is old, but unread data. In the slot connected to this signal, you
520 should always read everything that is available at that moment to make sure
521 that you don't lose any data.
522
523 \sa readStdout() readLineStdout() readyReadStderr()
524*/
525/*!
526 \fn void QProcess::readyReadStderr()
527
528 This signal is emitted when the process has written data to standard error.
529 You can read the data with readStderr().
530
531 Note that this signal is only emitted when there is new data and not
532 when there is old, but unread data. In the slot connected to this signal, you
533 should always read everything that is available at that moment to make sure
534 that you don't lose any data.
535
536 \sa readStderr() readLineStderr() readyReadStdout()
537*/
538/*!
539 \fn void QProcess::processExited()
540
541 This signal is emitted when the process has exited.
542
543 \sa isRunning() normalExit() exitStatus() start() launch()
544*/
545/*!
546 \fn void QProcess::wroteToStdin()
547
548 This signal is emitted if the data sent to standard input (via
549 writeToStdin()) was actually written to the process. This does not
550 imply that the process really read the data, since this class only detects
551 when it was able to write the data to the operating system. But it is now
552 safe to close standard input without losing pending data.
553
554 \sa writeToStdin() closeStdin()
555*/
556
557
558/*! \overload
559
560 The string \a buf is handled as text using
561 the QString::local8Bit() representation.
562*/
563void QProcess::writeToStdin( const QString& buf )
564{
565 QByteArray tmp = buf.local8Bit();
566 tmp.resize( buf.length() );
567 writeToStdin( tmp );
568}
569
570
571/*
572 * Under Windows the implementation is not so nice: it is not that easy to
573 * detect when one of the signals should be emitted; therefore there are some
574 * timers that query the information.
575 * To keep it a little efficient, use the timers only when they are needed.
576 * They are needed, if you are interested in the signals. So use
577 * connectNotify() and disconnectNotify() to keep track of your interest.
578 */
579/*! \reimp
580*/
581void QProcess::connectNotify( const char * signal )
582{
583#if defined(QT_QPROCESS_DEBUG)
584 qDebug( "QProcess::connectNotify(): signal %s has been connected", signal );
585#endif
586 if ( !ioRedirection )
587 if ( qstrcmp( signal, SIGNAL(readyReadStdout()) )==0 ||
588 qstrcmp( signal, SIGNAL(readyReadStderr()) )==0
589 ) {
590#if defined(QT_QPROCESS_DEBUG)
591 qDebug( "QProcess::connectNotify(): set ioRedirection to TRUE" );
592#endif
593 setIoRedirection( TRUE );
594 return;
595 }
596 if ( !notifyOnExit && qstrcmp( signal, SIGNAL(processExited()) )==0 ) {
597#if defined(QT_QPROCESS_DEBUG)
598 qDebug( "QProcess::connectNotify(): set notifyOnExit to TRUE" );
599#endif
600 setNotifyOnExit( TRUE );
601 return;
602 }
603 if ( !wroteToStdinConnected && qstrcmp( signal, SIGNAL(wroteToStdin()) )==0 ) {
604#if defined(QT_QPROCESS_DEBUG)
605 qDebug( "QProcess::connectNotify(): set wroteToStdinConnected to TRUE" );
606#endif
607 setWroteStdinConnected( TRUE );
608 return;
609 }
610}
611
612/*! \reimp
613*/
614void QProcess::disconnectNotify( const char * )
615{
616 if ( ioRedirection &&
617 receivers( SIGNAL(readyReadStdout()) ) ==0 &&
618 receivers( SIGNAL(readyReadStderr()) ) ==0
619 ) {
620#if defined(QT_QPROCESS_DEBUG)
621 qDebug( "QProcess::disconnectNotify(): set ioRedirection to FALSE" );
622#endif
623 setIoRedirection( FALSE );
624 }
625 if ( notifyOnExit && receivers( SIGNAL(processExited()) ) == 0 ) {
626#if defined(QT_QPROCESS_DEBUG)
627 qDebug( "QProcess::disconnectNotify(): set notifyOnExit to FALSE" );
628#endif
629 setNotifyOnExit( FALSE );
630 }
631 if ( wroteToStdinConnected && receivers( SIGNAL(wroteToStdin()) ) == 0 ) {
632#if defined(QT_QPROCESS_DEBUG)
633 qDebug( "QProcess::disconnectNotify(): set wroteToStdinConnected to FALSE" );
634#endif
635 setWroteStdinConnected( FALSE );
636 }
637}
638
639#endif // QT_NO_PROCESS
diff --git a/core/launcher/qprocess.h b/core/launcher/qprocess.h
new file mode 100644
index 0000000..0162234
--- a/dev/null
+++ b/core/launcher/qprocess.h
@@ -0,0 +1,163 @@
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#ifndef QPROCESS_H
22#define QPROCESS_H
23
24#include <qtopia/global.h>
25
26#ifndef QT_H
27#include "qobject.h"
28#include "qstringlist.h"
29#include "qdir.h"
30#endif // QT_H
31
32#ifndef QT_NO_PROCESS
33
34class QProcessPrivate;
35
36
37class Q_EXPORT QProcess : public QObject
38{
39 Q_OBJECT
40public:
41 QProcess( QObject *parent=0, const char *name=0 );
42 QProcess( const QString& arg0, QObject *parent=0, const char *name=0 );
43 QProcess( const QStringList& args, QObject *parent=0, const char *name=0 );
44 ~QProcess();
45
46 // set and get the arguments and working directory
47 QStringList arguments() const;
48 void clearArguments();
49 virtual void setArguments( const QStringList& args );
50 virtual void addArgument( const QString& arg );
51#ifndef QT_NO_DIR
52 QDir workingDirectory() const;
53 virtual void setWorkingDirectory( const QDir& dir );
54#endif
55
56 // priority
57 int priority() const;
58 void setPriority(int);
59
60 // set and get the comms wanted
61 enum Communication { Stdin=0x01, Stdout=0x02, Stderr=0x04, DupStderr=0x08 };
62 void setCommunication( int c );
63 int communication() const;
64
65 // start the execution
66 virtual bool start( QStringList *env=0 );
67 virtual bool launch( const QString& buf, QStringList *env=0 );
68 virtual bool launch( const QByteArray& buf, QStringList *env=0 );
69
70 // inquire the status
71 bool isRunning() const;
72 bool normalExit() const;
73 int exitStatus() const;
74
75 // reading
76 virtual QByteArray readStdout();
77 virtual QByteArray readStderr();
78 bool canReadLineStdout() const;
79 bool canReadLineStderr() const;
80 virtual QString readLineStdout();
81 virtual QString readLineStderr();
82
83 // get platform dependent process information
84#if defined(Q_OS_WIN32)
85 typedef void* PID;
86#else
87 typedef long Q_LONG;
88 typedef Q_LONG PID;
89#endif
90 PID processIdentifier();
91
92 void flushStdin();
93
94signals:
95 void readyReadStdout();
96 void readyReadStderr();
97 void processExited();
98 void wroteToStdin();
99 void launchFinished();
100
101public slots:
102 // end the execution
103 void tryTerminate() const;
104 void kill() const;
105
106 // input
107 virtual void writeToStdin( const QByteArray& buf );
108 virtual void writeToStdin( const QString& buf );
109 virtual void closeStdin();
110
111protected: // ### or private?
112 void connectNotify( const char * signal );
113 void disconnectNotify( const char * signal );
114private:
115 void setIoRedirection( bool value );
116 void setNotifyOnExit( bool value );
117 void setWroteStdinConnected( bool value );
118
119 void init();
120 void reset();
121#if defined(Q_OS_WIN32)
122 uint readStddev( HANDLE dev, char *buf, uint bytes );
123#endif
124 bool scanNewline( bool stdOut, QByteArray *store );
125
126 QByteArray* bufStdout();
127 QByteArray* bufStderr();
128 void consumeBufStdout( int consume );
129 void consumeBufStderr( int consume );
130
131private slots:
132 void socketRead( int fd );
133 void socketWrite( int fd );
134 void timeout();
135 void closeStdinLaunch();
136
137private:
138 QProcessPrivate *d;
139#ifndef QT_NO_DIR
140 QDir workingDir;
141#endif
142 QStringList _arguments;
143
144 int exitStat; // exit status
145 bool exitNormal; // normal exit?
146 bool ioRedirection; // automatically set be (dis)connectNotify
147 bool notifyOnExit; // automatically set be (dis)connectNotify
148 bool wroteToStdinConnected; // automatically set be (dis)connectNotify
149
150 bool readStdoutCalled;
151 bool readStderrCalled;
152 int comms;
153
154 friend class QProcessPrivate;
155#if defined(Q_OS_UNIX) || defined(_OS_UNIX) || defined(UNIX)
156 friend class QProcessManager;
157 friend class QProc;
158#endif
159};
160
161#endif // QT_NO_PROCESS
162
163#endif // QPROCESS_H
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