-rw-r--r-- | core/launcher/qprocess_unix.cpp | 2 |
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> |
30 | using namespace Opie::Core; | 30 | using 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 |
70 | extern "C" { | 70 | extern "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 | ||
85 | class QProc; | 85 | class QProc; |
86 | class QProcessManager; | 86 | class QProcessManager; |
87 | class QProcessPrivate | 87 | class QProcessPrivate |
88 | { | 88 | { |
89 | public: | 89 | public: |
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 | */ |
128 | class QProc | 128 | class QProc |
129 | { | 129 | { |
130 | public: | 130 | public: |
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 | **********************************************************************/ |
176 | class QProcessManager : public QObject | 176 | class QProcessManager : public QObject |
177 | { | 177 | { |
178 | Q_OBJECT | 178 | Q_OBJECT |
179 | 179 | ||
180 | public: | 180 | public: |
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 | ||
189 | public slots: | 189 | public slots: |
190 | void removeMe(); | 190 | void removeMe(); |
191 | void sigchldHnd( int ); | 191 | void sigchldHnd( int ); |
192 | 192 | ||
193 | public: | 193 | public: |
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 | ||
200 | QCleanupHandler<QProcessManager> qprocess_cleanup_procmanager; | 200 | QCleanupHandler<QProcessManager> qprocess_cleanup_procmanager; |
201 | 201 | ||
202 | QProcessManager::QProcessManager() | 202 | QProcessManager::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 | ||
257 | QProcessManager::~QProcessManager() | 257 | QProcessManager::~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 | ||
280 | void QProcessManager::append( QProc *p ) | 280 | void 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 | ||
288 | void QProcessManager::remove( QProc *p ) | 288 | void 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 | ||
297 | void QProcessManager::cleanup() | 297 | void 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 | ||
304 | void QProcessManager::removeMe() | 304 | void 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 | ||
313 | void QProcessManager::sigchldHnd( int fd ) | 313 | void 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 | **********************************************************************/ |
383 | QProcessManager *QProcessPrivate::procManager = 0; | 383 | QProcessManager *QProcessPrivate::procManager = 0; |
384 | 384 | ||
385 | QProcessPrivate::QProcessPrivate() | 385 | QProcessPrivate::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 | ||
402 | QProcessPrivate::~QProcessPrivate() | 402 | QProcessPrivate::~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 | */ |
429 | void QProcessPrivate::closeOpenSocketsForChild() | 429 | void 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 | ||
447 | void QProcessPrivate::newProc( pid_t pid, QProcess *process ) | 447 | void 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 | **********************************************************************/ |
463 | QT_SIGNAL_RETTYPE qt_C_sigchldHnd( QT_SIGNAL_ARGS ) | 463 | QT_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 | } |
473 | QT_SIGNAL_RETTYPE qt_C_sigpipeHnd( QT_SIGNAL_ARGS ) | 473 | QT_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 | */ |
487 | void QProcess::init() | 487 | void 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 | */ |
498 | void QProcess::reset() | 498 | void 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 | ||
508 | QByteArray* QProcess::bufStdout() | 508 | QByteArray* 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 | ||
518 | QByteArray* QProcess::bufStderr() | 518 | QByteArray* 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 | ||
528 | void QProcess::consumeBufStdout( int consume ) | 528 | void 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 | ||
540 | void QProcess::consumeBufStderr( int consume ) | 540 | void 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 | */ |
563 | QProcess::~QProcess() | 563 | QProcess::~QProcess() |
564 | { | 564 | { |
565 | delete d; | 565 | delete d; |
566 | } | 566 | } |
567 | 567 | ||