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