author | eilers <eilers> | 2004-04-10 13:29:30 (UTC) |
---|---|---|
committer | eilers <eilers> | 2004-04-10 13:29:30 (UTC) |
commit | 8350779f2628ce800b4bca7cef7d2b9bb644879e (patch) (unidiff) | |
tree | 90895aef8cede58449905601406e1119cd5d4a29 | |
parent | 24fcd64ca69588f3f6364dbc5e14df9f1686134a (diff) | |
download | opie-8350779f2628ce800b4bca7cef7d2b9bb644879e.zip opie-8350779f2628ce800b4bca7cef7d2b9bb644879e.tar.gz opie-8350779f2628ce800b4bca7cef7d2b9bb644879e.tar.bz2 |
resource.h must stay behind time.h to compile on mac
-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,1173 +1,1173 @@ | |||
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 | ||
568 | /*! | 568 | /*! |
569 | Tries to run a process for the command and arguments that were specified with | 569 | Tries to run a process for the command and arguments that were specified with |
570 | setArguments(), addArgument() or that were specified in the constructor. The | 570 | setArguments(), addArgument() or that were specified in the constructor. The |
571 | command is searched in the path for executable programs; you can also use an | 571 | command is searched in the path for executable programs; you can also use an |
572 | absolute path to the command. | 572 | absolute path to the command. |
573 | 573 | ||
574 | If \a env is null, then the process is started with the same environment as | 574 | If \a env is null, then the process is started with the same environment as |
575 | the starting process. If \a env is non-null, then the values in the | 575 | the starting process. If \a env is non-null, then the values in the |
576 | stringlist are interpreted as environment setttings of the form \c | 576 | stringlist are interpreted as environment setttings of the form \c |
577 | {key=value} and the process is started in these environment settings. For | 577 | {key=value} and the process is started in these environment settings. For |
578 | convenience, there is a small exception to this rule: under Unix, if \a env | 578 | convenience, there is a small exception to this rule: under Unix, if \a env |
579 | does not contain any settings for the environment variable \c | 579 | does not contain any settings for the environment variable \c |
580 | LD_LIBRARY_PATH, then this variable is inherited from the starting process; | 580 | LD_LIBRARY_PATH, then this variable is inherited from the starting process; |
581 | under Windows the same applies for the enverionment varialbe \c PATH. | 581 | under Windows the same applies for the enverionment varialbe \c PATH. |
582 | 582 | ||
583 | Returns TRUE if the process could be started, otherwise FALSE. | 583 | Returns TRUE if the process could be started, otherwise FALSE. |
584 | 584 | ||
585 | You can write data to standard input of the process with | 585 | You can write data to standard input of the process with |
586 | writeToStdin(), you can close standard input with closeStdin() and you can | 586 | writeToStdin(), you can close standard input with closeStdin() and you can |
587 | terminate the process tryTerminate() resp. kill(). | 587 | terminate the process tryTerminate() resp. kill(). |
588 | 588 | ||
589 | You can call this function even when there already is a running | 589 | You can call this function even when there already is a running |
590 | process in this object. In this case, QProcess closes standard input | 590 | process in this object. In this case, QProcess closes standard input |
591 | of the old process and deletes pending data, i.e., you loose all | 591 | of the old process and deletes pending data, i.e., you loose all |
592 | control over that process, but the process is not terminated. This applies | 592 | control over that process, but the process is not terminated. This applies |
593 | also if the process could not be started. (On operating systems that have | 593 | also if the process could not be started. (On operating systems that have |
594 | zombie processes, Qt will also wait() on the old process.) | 594 | zombie processes, Qt will also wait() on the old process.) |
595 | 595 | ||
596 | \sa launch() closeStdin() | 596 | \sa launch() closeStdin() |
597 | */ | 597 | */ |
598 | bool QProcess::start( QStringList *env ) | 598 | bool QProcess::start( QStringList *env ) |
599 | { | 599 | { |
600 | #if defined(QT_QPROCESS_DEBUG) | 600 | #if defined(QT_QPROCESS_DEBUG) |
601 | odebug << "QProcess::start()" << oendl; | 601 | odebug << "QProcess::start()" << oendl; |
602 | #endif | 602 | #endif |
603 | reset(); | 603 | reset(); |
604 | 604 | ||
605 | int sStdin[2]; | 605 | int sStdin[2]; |
606 | int sStdout[2]; | 606 | int sStdout[2]; |
607 | int sStderr[2]; | 607 | int sStderr[2]; |
608 | 608 | ||
609 | // open sockets for piping | 609 | // open sockets for piping |
610 | if ( (comms & Stdin) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdin ) == -1 ) { | 610 | if ( (comms & Stdin) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdin ) == -1 ) { |
611 | return FALSE; | 611 | return FALSE; |
612 | } | 612 | } |
613 | if ( (comms & Stderr) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStderr ) == -1 ) { | 613 | if ( (comms & Stderr) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStderr ) == -1 ) { |
614 | return FALSE; | 614 | return FALSE; |
615 | } | 615 | } |
616 | if ( (comms & Stdout) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdout ) == -1 ) { | 616 | if ( (comms & Stdout) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdout ) == -1 ) { |
617 | return FALSE; | 617 | return FALSE; |
618 | } | 618 | } |
619 | 619 | ||
620 | // the following pipe is only used to determine if the process could be | 620 | // the following pipe is only used to determine if the process could be |
621 | // started | 621 | // started |
622 | int fd[2]; | 622 | int fd[2]; |
623 | if ( pipe( fd ) < 0 ) { | 623 | if ( pipe( fd ) < 0 ) { |
624 | // non critical error, go on | 624 | // non critical error, go on |
625 | fd[0] = 0; | 625 | fd[0] = 0; |
626 | fd[1] = 0; | 626 | fd[1] = 0; |
627 | } | 627 | } |
628 | 628 | ||
629 | // construct the arguments for exec | 629 | // construct the arguments for exec |
630 | QCString *arglistQ = new QCString[ _arguments.count() + 1 ]; | 630 | QCString *arglistQ = new QCString[ _arguments.count() + 1 ]; |
631 | const char** arglist = new const char*[ _arguments.count() + 1 ]; | 631 | const char** arglist = new const char*[ _arguments.count() + 1 ]; |
632 | int i = 0; | 632 | int i = 0; |
633 | for ( QStringList::Iterator it = _arguments.begin(); it != _arguments.end(); ++it ) { | 633 | for ( QStringList::Iterator it = _arguments.begin(); it != _arguments.end(); ++it ) { |
634 | arglistQ[i] = (*it).local8Bit(); | 634 | arglistQ[i] = (*it).local8Bit(); |
635 | arglist[i] = arglistQ[i]; | 635 | arglist[i] = arglistQ[i]; |
636 | #if defined(QT_QPROCESS_DEBUG) | 636 | #if defined(QT_QPROCESS_DEBUG) |
637 | odebug << "QProcess::start(): arg " << i << " = " << arglist[i] << "" << oendl; | 637 | odebug << "QProcess::start(): arg " << i << " = " << arglist[i] << "" << oendl; |
638 | #endif | 638 | #endif |
639 | i++; | 639 | i++; |
640 | } | 640 | } |
641 | arglist[i] = 0; | 641 | arglist[i] = 0; |
642 | 642 | ||
643 | // Must make sure signal handlers are installed before exec'ing | 643 | // Must make sure signal handlers are installed before exec'ing |
644 | // in case the process exits quickly. | 644 | // in case the process exits quickly. |
645 | if ( d->procManager == 0 ) { | 645 | if ( d->procManager == 0 ) { |
646 | d->procManager = new QProcessManager; | 646 | d->procManager = new QProcessManager; |
647 | qprocess_cleanup_procmanager.add( &d->procManager ); | 647 | qprocess_cleanup_procmanager.add( &d->procManager ); |
648 | } | 648 | } |
649 | 649 | ||
650 | // fork and exec | 650 | // fork and exec |
651 | QApplication::flushX(); | 651 | QApplication::flushX(); |
652 | pid_t pid = fork(); | 652 | pid_t pid = fork(); |
653 | if ( pid == 0 ) { | 653 | if ( pid == 0 ) { |
654 | // child | 654 | // child |
655 | d->closeOpenSocketsForChild(); | 655 | d->closeOpenSocketsForChild(); |
656 | if ( comms & Stdin ) { | 656 | if ( comms & Stdin ) { |
657 | ::close( sStdin[1] ); | 657 | ::close( sStdin[1] ); |
658 | ::dup2( sStdin[0], STDIN_FILENO ); | 658 | ::dup2( sStdin[0], STDIN_FILENO ); |
659 | } | 659 | } |
660 | if ( comms & Stdout ) { | 660 | if ( comms & Stdout ) { |
661 | ::close( sStdout[0] ); | 661 | ::close( sStdout[0] ); |
662 | ::dup2( sStdout[1], STDOUT_FILENO ); | 662 | ::dup2( sStdout[1], STDOUT_FILENO ); |
663 | } | 663 | } |
664 | if ( comms & Stderr ) { | 664 | if ( comms & Stderr ) { |
665 | ::close( sStderr[0] ); | 665 | ::close( sStderr[0] ); |
666 | ::dup2( sStderr[1], STDERR_FILENO ); | 666 | ::dup2( sStderr[1], STDERR_FILENO ); |
667 | } | 667 | } |
668 | if ( comms & DupStderr ) { | 668 | if ( comms & DupStderr ) { |
669 | ::dup2( STDOUT_FILENO, STDERR_FILENO ); | 669 | ::dup2( STDOUT_FILENO, STDERR_FILENO ); |
670 | } | 670 | } |
671 | #ifndef QT_NO_DIR | 671 | #ifndef QT_NO_DIR |
672 | ::chdir( workingDir.absPath().latin1() ); | 672 | ::chdir( workingDir.absPath().latin1() ); |
673 | #endif | 673 | #endif |
674 | if ( fd[0] ) | 674 | if ( fd[0] ) |
675 | ::close( fd[0] ); | 675 | ::close( fd[0] ); |
676 | if ( fd[1] ) | 676 | if ( fd[1] ) |
677 | ::fcntl( fd[1], F_SETFD, FD_CLOEXEC ); // close on exec shows sucess | 677 | ::fcntl( fd[1], F_SETFD, FD_CLOEXEC ); // close on exec shows sucess |
678 | 678 | ||
679 | if ( env == 0 ) { // inherit environment and start process | 679 | if ( env == 0 ) { // inherit environment and start process |
680 | ::execvp( arglist[0], (char*const*)arglist ); // ### cast not nice | 680 | ::execvp( arglist[0], (char*const*)arglist ); // ### cast not nice |
681 | } else { // start process with environment settins as specified in env | 681 | } else { // start process with environment settins as specified in env |
682 | // construct the environment for exec | 682 | // construct the environment for exec |
683 | int numEntries = env->count(); | 683 | int numEntries = env->count(); |
684 | bool setLibraryPath = | 684 | bool setLibraryPath = |
685 | env->grep( QRegExp( "^LD_LIBRARY_PATH=" ) ).isEmpty() && | 685 | env->grep( QRegExp( "^LD_LIBRARY_PATH=" ) ).isEmpty() && |
686 | getenv( "LD_LIBRARY_PATH" ) != 0; | 686 | getenv( "LD_LIBRARY_PATH" ) != 0; |
687 | if ( setLibraryPath ) | 687 | if ( setLibraryPath ) |
688 | numEntries++; | 688 | numEntries++; |
689 | QCString *envlistQ = new QCString[ numEntries + 1 ]; | 689 | QCString *envlistQ = new QCString[ numEntries + 1 ]; |
690 | const char** envlist = new const char*[ numEntries + 1 ]; | 690 | const char** envlist = new const char*[ numEntries + 1 ]; |
691 | int i = 0; | 691 | int i = 0; |
692 | if ( setLibraryPath ) { | 692 | if ( setLibraryPath ) { |
693 | envlistQ[i] = QString( "LD_LIBRARY_PATH=%1" ).arg( getenv( "LD_LIBRARY_PATH" ) ).local8Bit(); | 693 | envlistQ[i] = QString( "LD_LIBRARY_PATH=%1" ).arg( getenv( "LD_LIBRARY_PATH" ) ).local8Bit(); |
694 | envlist[i] = envlistQ[i]; | 694 | envlist[i] = envlistQ[i]; |
695 | i++; | 695 | i++; |
696 | } | 696 | } |
697 | for ( QStringList::Iterator it = env->begin(); it != env->end(); ++it ) { | 697 | for ( QStringList::Iterator it = env->begin(); it != env->end(); ++it ) { |
698 | envlistQ[i] = (*it).local8Bit(); | 698 | envlistQ[i] = (*it).local8Bit(); |
699 | envlist[i] = envlistQ[i]; | 699 | envlist[i] = envlistQ[i]; |
700 | i++; | 700 | i++; |
701 | } | 701 | } |
702 | envlist[i] = 0; | 702 | envlist[i] = 0; |
703 | 703 | ||
704 | // look for the executable in the search path | 704 | // look for the executable in the search path |
705 | if ( _arguments.count()>0 && getenv("PATH")!=0 ) { | 705 | if ( _arguments.count()>0 && getenv("PATH")!=0 ) { |
706 | QString command = _arguments[0]; | 706 | QString command = _arguments[0]; |
707 | if ( !command.contains( '/' ) ) { | 707 | if ( !command.contains( '/' ) ) { |
708 | QStringList pathList = QStringList::split( ':', getenv( "PATH" ) ); | 708 | QStringList pathList = QStringList::split( ':', getenv( "PATH" ) ); |
709 | for (QStringList::Iterator it = pathList.begin(); it != pathList.end(); ++it ) { | 709 | for (QStringList::Iterator it = pathList.begin(); it != pathList.end(); ++it ) { |
710 | QString dir = *it; | 710 | QString dir = *it; |
711 | #ifdef Q_OS_MACX | 711 | #ifdef Q_OS_MACX |
712 | if(QFile::exists(dir + "/" + command + ".app")) //look in a bundle | 712 | if(QFile::exists(dir + "/" + command + ".app")) //look in a bundle |
713 | dir += "/" + command + ".app/Contents/MacOS"; | 713 | dir += "/" + command + ".app/Contents/MacOS"; |
714 | #endif | 714 | #endif |
715 | #ifndef QT_NO_DIR | 715 | #ifndef QT_NO_DIR |
716 | QFileInfo fileInfo( dir, command ); | 716 | QFileInfo fileInfo( dir, command ); |
717 | #else | 717 | #else |
718 | QFileInfo fileInfo( dir + "/" + command ); | 718 | QFileInfo fileInfo( dir + "/" + command ); |
719 | #endif | 719 | #endif |
720 | if ( fileInfo.isExecutable() ) { | 720 | if ( fileInfo.isExecutable() ) { |
721 | arglistQ[0] = fileInfo.filePath().local8Bit(); | 721 | arglistQ[0] = fileInfo.filePath().local8Bit(); |
722 | arglist[0] = arglistQ[0]; | 722 | arglist[0] = arglistQ[0]; |
723 | break; | 723 | break; |
724 | } | 724 | } |
725 | } | 725 | } |
726 | } | 726 | } |
727 | } | 727 | } |
728 | ::execve( arglist[0], (char*const*)arglist, (char*const*)envlist ); // ### casts not nice | 728 | ::execve( arglist[0], (char*const*)arglist, (char*const*)envlist ); // ### casts not nice |
729 | } | 729 | } |
730 | if ( fd[1] ) { | 730 | if ( fd[1] ) { |
731 | char buf = 0; | 731 | char buf = 0; |
732 | ::write( fd[1], &buf, 1 ); | 732 | ::write( fd[1], &buf, 1 ); |
733 | ::close( fd[1] ); | 733 | ::close( fd[1] ); |
734 | } | 734 | } |
735 | ::exit( -1 ); | 735 | ::exit( -1 ); |
736 | } else if ( pid == -1 ) { | 736 | } else if ( pid == -1 ) { |
737 | // error forking | 737 | // error forking |
738 | goto error; | 738 | goto error; |
739 | } | 739 | } |
740 | 740 | ||
741 | // test if exec was successful | 741 | // test if exec was successful |
742 | if ( fd[1] ) | 742 | if ( fd[1] ) |
743 | ::close( fd[1] ); | 743 | ::close( fd[1] ); |
744 | if ( fd[0] ) { | 744 | if ( fd[0] ) { |
745 | char buf; | 745 | char buf; |
746 | for ( ;; ) { | 746 | for ( ;; ) { |
747 | int n = ::read( fd[0], &buf, 1 ); | 747 | int n = ::read( fd[0], &buf, 1 ); |
748 | if ( n==1 ) { | 748 | if ( n==1 ) { |
749 | // socket was not closed => error | 749 | // socket was not closed => error |
750 | d->proc = 0; | 750 | d->proc = 0; |
751 | goto error; | 751 | goto error; |
752 | } else if ( n==-1 ) { | 752 | } else if ( n==-1 ) { |
753 | if ( errno==EAGAIN || errno==EINTR ) | 753 | if ( errno==EAGAIN || errno==EINTR ) |
754 | // try it again | 754 | // try it again |
755 | continue; | 755 | continue; |
756 | } | 756 | } |
757 | break; | 757 | break; |
758 | } | 758 | } |
759 | ::close( fd[0] ); | 759 | ::close( fd[0] ); |
760 | } | 760 | } |
761 | 761 | ||
762 | d->newProc( pid, this ); | 762 | d->newProc( pid, this ); |
763 | 763 | ||
764 | if ( comms & Stdin ) { | 764 | if ( comms & Stdin ) { |
765 | ::close( sStdin[0] ); | 765 | ::close( sStdin[0] ); |
766 | d->proc->socketStdin = sStdin[1]; | 766 | d->proc->socketStdin = sStdin[1]; |
767 | d->notifierStdin = new QSocketNotifier( sStdin[1], QSocketNotifier::Write ); | 767 | d->notifierStdin = new QSocketNotifier( sStdin[1], QSocketNotifier::Write ); |
768 | connect( d->notifierStdin, SIGNAL(activated(int)), | 768 | connect( d->notifierStdin, SIGNAL(activated(int)), |
769 | this, SLOT(socketWrite(int)) ); | 769 | this, SLOT(socketWrite(int)) ); |
770 | // setup notifiers for the sockets | 770 | // setup notifiers for the sockets |
771 | if ( !d->stdinBuf.isEmpty() ) { | 771 | if ( !d->stdinBuf.isEmpty() ) { |
772 | d->notifierStdin->setEnabled( TRUE ); | 772 | d->notifierStdin->setEnabled( TRUE ); |
773 | } | 773 | } |
774 | } | 774 | } |
775 | if ( comms & Stdout ) { | 775 | if ( comms & Stdout ) { |
776 | ::close( sStdout[1] ); | 776 | ::close( sStdout[1] ); |
777 | d->proc->socketStdout = sStdout[0]; | 777 | d->proc->socketStdout = sStdout[0]; |
778 | d->notifierStdout = new QSocketNotifier( sStdout[0], QSocketNotifier::Read ); | 778 | d->notifierStdout = new QSocketNotifier( sStdout[0], QSocketNotifier::Read ); |
779 | connect( d->notifierStdout, SIGNAL(activated(int)), | 779 | connect( d->notifierStdout, SIGNAL(activated(int)), |
780 | this, SLOT(socketRead(int)) ); | 780 | this, SLOT(socketRead(int)) ); |
781 | if ( ioRedirection ) | 781 | if ( ioRedirection ) |
782 | d->notifierStdout->setEnabled( TRUE ); | 782 | d->notifierStdout->setEnabled( TRUE ); |
783 | } | 783 | } |
784 | if ( comms & Stderr ) { | 784 | if ( comms & Stderr ) { |
785 | ::close( sStderr[1] ); | 785 | ::close( sStderr[1] ); |
786 | d->proc->socketStderr = sStderr[0]; | 786 | d->proc->socketStderr = sStderr[0]; |
787 | d->notifierStderr = new QSocketNotifier( sStderr[0], QSocketNotifier::Read ); | 787 | d->notifierStderr = new QSocketNotifier( sStderr[0], QSocketNotifier::Read ); |
788 | connect( d->notifierStderr, SIGNAL(activated(int)), | 788 | connect( d->notifierStderr, SIGNAL(activated(int)), |
789 | this, SLOT(socketRead(int)) ); | 789 | this, SLOT(socketRead(int)) ); |
790 | if ( ioRedirection ) | 790 | if ( ioRedirection ) |
791 | d->notifierStderr->setEnabled( TRUE ); | 791 | d->notifierStderr->setEnabled( TRUE ); |
792 | } | 792 | } |
793 | 793 | ||
794 | // cleanup and return | 794 | // cleanup and return |
795 | delete[] arglistQ; | 795 | delete[] arglistQ; |
796 | delete[] arglist; | 796 | delete[] arglist; |
797 | return TRUE; | 797 | return TRUE; |
798 | 798 | ||
799 | error: | 799 | error: |
800 | #if defined(QT_QPROCESS_DEBUG) | 800 | #if defined(QT_QPROCESS_DEBUG) |
801 | odebug << "QProcess::start(): error starting process" << oendl; | 801 | odebug << "QProcess::start(): error starting process" << oendl; |
802 | #endif | 802 | #endif |
803 | if ( d->procManager ) | 803 | if ( d->procManager ) |
804 | d->procManager->cleanup(); | 804 | d->procManager->cleanup(); |
805 | if ( comms & Stdin ) { | 805 | if ( comms & Stdin ) { |
806 | ::close( sStdin[1] ); | 806 | ::close( sStdin[1] ); |
807 | ::close( sStdin[0] ); | 807 | ::close( sStdin[0] ); |
808 | } | 808 | } |
809 | if ( comms & Stdout ) { | 809 | if ( comms & Stdout ) { |
810 | ::close( sStdout[0] ); | 810 | ::close( sStdout[0] ); |
811 | ::close( sStdout[1] ); | 811 | ::close( sStdout[1] ); |
812 | } | 812 | } |
813 | if ( comms & Stderr ) { | 813 | if ( comms & Stderr ) { |
814 | ::close( sStderr[0] ); | 814 | ::close( sStderr[0] ); |
815 | ::close( sStderr[1] ); | 815 | ::close( sStderr[1] ); |
816 | } | 816 | } |
817 | ::close( fd[0] ); | 817 | ::close( fd[0] ); |
818 | ::close( fd[1] ); | 818 | ::close( fd[1] ); |
819 | delete[] arglistQ; | 819 | delete[] arglistQ; |
820 | delete[] arglist; | 820 | delete[] arglist; |
821 | return FALSE; | 821 | return FALSE; |
822 | } | 822 | } |
823 | 823 | ||
824 | 824 | ||
825 | /*! | 825 | /*! |
826 | Asks the process to terminate. Processes can ignore this wish. If you want to | 826 | Asks the process to terminate. Processes can ignore this wish. If you want to |
827 | be sure that the process really terminates, you must use kill() instead. | 827 | be sure that the process really terminates, you must use kill() instead. |
828 | 828 | ||
829 | The slot returns immediately: it does not wait until the process has | 829 | The slot returns immediately: it does not wait until the process has |
830 | finished. When the process really exited, the signal processExited() is | 830 | finished. When the process really exited, the signal processExited() is |
831 | emitted. | 831 | emitted. |
832 | 832 | ||
833 | \sa kill() processExited() | 833 | \sa kill() processExited() |
834 | */ | 834 | */ |
835 | void QProcess::tryTerminate() const | 835 | void QProcess::tryTerminate() const |
836 | { | 836 | { |
837 | if ( d->proc != 0 ) | 837 | if ( d->proc != 0 ) |
838 | ::kill( d->proc->pid, SIGTERM ); | 838 | ::kill( d->proc->pid, SIGTERM ); |
839 | } | 839 | } |
840 | 840 | ||
841 | /*! | 841 | /*! |
842 | Terminates the process. This is not a safe way to end a process since the | 842 | Terminates the process. This is not a safe way to end a process since the |
843 | process will not be able to do cleanup. tryTerminate() is a safer way to do | 843 | process will not be able to do cleanup. tryTerminate() is a safer way to do |
844 | it, but processes might ignore a tryTerminate(). | 844 | it, but processes might ignore a tryTerminate(). |
845 | 845 | ||
846 | The nice way to end a process and to be sure that it is finished, is doing | 846 | The nice way to end a process and to be sure that it is finished, is doing |
847 | something like this: | 847 | something like this: |
848 | \code | 848 | \code |
849 | process->tryTerminate(); | 849 | process->tryTerminate(); |
850 | QTimer::singleShot( 5000, process, SLOT( kill() ) ); | 850 | QTimer::singleShot( 5000, process, SLOT( kill() ) ); |
851 | \endcode | 851 | \endcode |
852 | 852 | ||
853 | This tries to terminate the process the nice way. If the process is still | 853 | This tries to terminate the process the nice way. If the process is still |
854 | running after 5 seconds, it terminates the process the hard way. The timeout | 854 | running after 5 seconds, it terminates the process the hard way. The timeout |
855 | should be chosen depending on the time the process needs to do all the | 855 | should be chosen depending on the time the process needs to do all the |
856 | cleanup: use a higher value if the process is likely to do heavy computation | 856 | cleanup: use a higher value if the process is likely to do heavy computation |
857 | on cleanup. | 857 | on cleanup. |
858 | 858 | ||
859 | The slot returns immediately: it does not wait until the process has | 859 | The slot returns immediately: it does not wait until the process has |
860 | finished. When the process really exited, the signal processExited() is | 860 | finished. When the process really exited, the signal processExited() is |
861 | emitted. | 861 | emitted. |
862 | 862 | ||
863 | \sa tryTerminate() processExited() | 863 | \sa tryTerminate() processExited() |
864 | */ | 864 | */ |
865 | void QProcess::kill() const | 865 | void QProcess::kill() const |
866 | { | 866 | { |
867 | if ( d->proc != 0 ) | 867 | if ( d->proc != 0 ) |
868 | ::kill( d->proc->pid, SIGKILL ); | 868 | ::kill( d->proc->pid, SIGKILL ); |
869 | } | 869 | } |
870 | 870 | ||
871 | /*! | 871 | /*! |
872 | Returns TRUE if the process is running, otherwise FALSE. | 872 | Returns TRUE if the process is running, otherwise FALSE. |
873 | 873 | ||
874 | \sa normalExit() exitStatus() processExited() | 874 | \sa normalExit() exitStatus() processExited() |
875 | */ | 875 | */ |
876 | bool QProcess::isRunning() const | 876 | bool QProcess::isRunning() const |
877 | { | 877 | { |
878 | if ( d->exitValuesCalculated ) { | 878 | if ( d->exitValuesCalculated ) { |
879 | #if defined(QT_QPROCESS_DEBUG) | 879 | #if defined(QT_QPROCESS_DEBUG) |
880 | odebug << "QProcess::isRunning(): FALSE (already computed)" << oendl; | 880 | odebug << "QProcess::isRunning(): FALSE (already computed)" << oendl; |
881 | #endif | 881 | #endif |
882 | return FALSE; | 882 | return FALSE; |
883 | } | 883 | } |
884 | if ( d->proc == 0 ) | 884 | if ( d->proc == 0 ) |
885 | return FALSE; | 885 | return FALSE; |
886 | int status; | 886 | int status; |
887 | if ( ::waitpid( d->proc->pid, &status, WNOHANG ) == d->proc->pid ) | 887 | if ( ::waitpid( d->proc->pid, &status, WNOHANG ) == d->proc->pid ) |
888 | { | 888 | { |
889 | // compute the exit values | 889 | // compute the exit values |
890 | QProcess *that = (QProcess*)this; // mutable | 890 | QProcess *that = (QProcess*)this; // mutable |
891 | that->exitNormal = WIFEXITED( status ) != 0; | 891 | that->exitNormal = WIFEXITED( status ) != 0; |
892 | if ( exitNormal ) { | 892 | if ( exitNormal ) { |
893 | that->exitStat = (char)WEXITSTATUS( status ); | 893 | that->exitStat = (char)WEXITSTATUS( status ); |
894 | } | 894 | } |
895 | d->exitValuesCalculated = TRUE; | 895 | d->exitValuesCalculated = TRUE; |
896 | #if defined(QT_QPROCESS_DEBUG) | 896 | #if defined(QT_QPROCESS_DEBUG) |
897 | odebug << "QProcess::isRunning() (PID: " << d->proc->pid << "): FALSE" << oendl; | 897 | odebug << "QProcess::isRunning() (PID: " << d->proc->pid << "): FALSE" << oendl; |
898 | #endif | 898 | #endif |
899 | return FALSE; | 899 | return FALSE; |
900 | } | 900 | } |
901 | #if defined(QT_QPROCESS_DEBUG) | 901 | #if defined(QT_QPROCESS_DEBUG) |
902 | odebug << "QProcess::isRunning() (PID: " << d->proc->pid << "): TRUE" << oendl; | 902 | odebug << "QProcess::isRunning() (PID: " << d->proc->pid << "): TRUE" << oendl; |
903 | #endif | 903 | #endif |
904 | return TRUE; | 904 | return TRUE; |
905 | } | 905 | } |
906 | 906 | ||
907 | /*! | 907 | /*! |
908 | Writes the data \a buf to the standard input of the process. The process may | 908 | Writes the data \a buf to the standard input of the process. The process may |
909 | or may not read this data. | 909 | or may not read this data. |
910 | 910 | ||
911 | This function returns immediately; the QProcess class might write the data at | 911 | This function returns immediately; the QProcess class might write the data at |
912 | a later point (you have to enter the event loop for that). When all the data | 912 | a later point (you have to enter the event loop for that). When all the data |
913 | is written to the process, the signal wroteToStdin() is emitted. This does | 913 | is written to the process, the signal wroteToStdin() is emitted. This does |
914 | not mean that the process really read the data, since this class only detects | 914 | not mean that the process really read the data, since this class only detects |
915 | when it was able to write the data to the operating system. | 915 | when it was able to write the data to the operating system. |
916 | 916 | ||
917 | \sa wroteToStdin() closeStdin() readStdout() readStderr() | 917 | \sa wroteToStdin() closeStdin() readStdout() readStderr() |
918 | */ | 918 | */ |
919 | void QProcess::writeToStdin( const QByteArray& buf ) | 919 | void QProcess::writeToStdin( const QByteArray& buf ) |
920 | { | 920 | { |
921 | #if defined(QT_QPROCESS_DEBUG) | 921 | #if defined(QT_QPROCESS_DEBUG) |
922 | // odebug << "QProcess::writeToStdin(): write to stdin (" << d->socketStdin << ")" << oendl; | 922 | // odebug << "QProcess::writeToStdin(): write to stdin (" << d->socketStdin << ")" << oendl; |
923 | #endif | 923 | #endif |
924 | d->stdinBuf.enqueue( new QByteArray(buf) ); | 924 | d->stdinBuf.enqueue( new QByteArray(buf) ); |
925 | if ( d->notifierStdin != 0 ) | 925 | if ( d->notifierStdin != 0 ) |
926 | d->notifierStdin->setEnabled( TRUE ); | 926 | d->notifierStdin->setEnabled( TRUE ); |
927 | } | 927 | } |
928 | 928 | ||
929 | 929 | ||
930 | /*! | 930 | /*! |
931 | Closes standard input of the process. | 931 | Closes standard input of the process. |
932 | 932 | ||
933 | This function also deletes pending data that is not written to standard input | 933 | This function also deletes pending data that is not written to standard input |
934 | yet. | 934 | yet. |
935 | 935 | ||
936 | \sa wroteToStdin() | 936 | \sa wroteToStdin() |
937 | */ | 937 | */ |
938 | void QProcess::closeStdin() | 938 | void QProcess::closeStdin() |
939 | { | 939 | { |
940 | if ( d->proc == 0 ) | 940 | if ( d->proc == 0 ) |
941 | return; | 941 | return; |
942 | if ( d->proc->socketStdin !=0 ) { | 942 | if ( d->proc->socketStdin !=0 ) { |
943 | while ( !d->stdinBuf.isEmpty() ) { | 943 | while ( !d->stdinBuf.isEmpty() ) { |
944 | delete d->stdinBuf.dequeue(); | 944 | delete d->stdinBuf.dequeue(); |
945 | } | 945 | } |
946 | delete d->notifierStdin; | 946 | delete d->notifierStdin; |
947 | d->notifierStdin = 0; | 947 | d->notifierStdin = 0; |
948 | if ( ::close( d->proc->socketStdin ) != 0 ) { | 948 | if ( ::close( d->proc->socketStdin ) != 0 ) { |
949 | owarn << "Could not close stdin of child process" << oendl; | 949 | owarn << "Could not close stdin of child process" << oendl; |
950 | } | 950 | } |
951 | #if defined(QT_QPROCESS_DEBUG) | 951 | #if defined(QT_QPROCESS_DEBUG) |
952 | odebug << "QProcess::closeStdin(): stdin (" << d->proc->socketStdin << ") closed" << oendl; | 952 | odebug << "QProcess::closeStdin(): stdin (" << d->proc->socketStdin << ") closed" << oendl; |
953 | #endif | 953 | #endif |
954 | d->proc->socketStdin = 0; | 954 | d->proc->socketStdin = 0; |
955 | } | 955 | } |
956 | } | 956 | } |
957 | 957 | ||
958 | 958 | ||
959 | /* | 959 | /* |
960 | This private slot is called when the process has outputted data to either | 960 | This private slot is called when the process has outputted data to either |
961 | standard output or standard error. | 961 | standard output or standard error. |
962 | */ | 962 | */ |
963 | void QProcess::socketRead( int fd ) | 963 | void QProcess::socketRead( int fd ) |
964 | { | 964 | { |
965 | if ( d->socketReadCalled ) { | 965 | if ( d->socketReadCalled ) { |
966 | // the slots that are connected to the readyRead...() signals might | 966 | // the slots that are connected to the readyRead...() signals might |
967 | // trigger a recursive call of socketRead(). Avoid this since you get a | 967 | // trigger a recursive call of socketRead(). Avoid this since you get a |
968 | // blocking read otherwise. | 968 | // blocking read otherwise. |
969 | return; | 969 | return; |
970 | } | 970 | } |
971 | #if defined(QT_QPROCESS_DEBUG) | 971 | #if defined(QT_QPROCESS_DEBUG) |
972 | odebug << "QProcess::socketRead(): " << fd << "" << oendl; | 972 | odebug << "QProcess::socketRead(): " << fd << "" << oendl; |
973 | #endif | 973 | #endif |
974 | if ( fd == 0 ) | 974 | if ( fd == 0 ) |
975 | return; | 975 | return; |
976 | const int bufsize = 4096; | 976 | const int bufsize = 4096; |
977 | QByteArray *buffer = 0; | 977 | QByteArray *buffer = 0; |
978 | uint oldSize; | 978 | uint oldSize; |
979 | int n; | 979 | int n; |
980 | if ( fd == d->proc->socketStdout ) { | 980 | if ( fd == d->proc->socketStdout ) { |
981 | buffer = &d->bufStdout; | 981 | buffer = &d->bufStdout; |
982 | } else if ( fd == d->proc->socketStderr ) { | 982 | } else if ( fd == d->proc->socketStderr ) { |
983 | buffer = &d->bufStderr; | 983 | buffer = &d->bufStderr; |
984 | } else { | 984 | } else { |
985 | // this case should never happen, but just to be safe | 985 | // this case should never happen, but just to be safe |
986 | return; | 986 | return; |
987 | } | 987 | } |
988 | 988 | ||
989 | // read data | 989 | // read data |
990 | oldSize = buffer->size(); | 990 | oldSize = buffer->size(); |
991 | buffer->resize( oldSize + bufsize ); | 991 | buffer->resize( oldSize + bufsize ); |
992 | n = ::read( fd, buffer->data()+oldSize, bufsize ); | 992 | n = ::read( fd, buffer->data()+oldSize, bufsize ); |
993 | if ( n > 0 ) | 993 | if ( n > 0 ) |
994 | buffer->resize( oldSize + n ); | 994 | buffer->resize( oldSize + n ); |
995 | else | 995 | else |
996 | buffer->resize( oldSize ); | 996 | buffer->resize( oldSize ); |
997 | // eof or error? | 997 | // eof or error? |
998 | if ( n == 0 || n == -1 ) { | 998 | if ( n == 0 || n == -1 ) { |
999 | if ( fd == d->proc->socketStdout ) { | 999 | if ( fd == d->proc->socketStdout ) { |
1000 | #if defined(QT_QPROCESS_DEBUG) | 1000 | #if defined(QT_QPROCESS_DEBUG) |
1001 | odebug << "QProcess::socketRead(): stdout (" << fd << ") closed" << oendl; | 1001 | odebug << "QProcess::socketRead(): stdout (" << fd << ") closed" << oendl; |
1002 | #endif | 1002 | #endif |
1003 | d->notifierStdout->setEnabled( FALSE ); | 1003 | d->notifierStdout->setEnabled( FALSE ); |
1004 | delete d->notifierStdout; | 1004 | delete d->notifierStdout; |
1005 | d->notifierStdout = 0; | 1005 | d->notifierStdout = 0; |
1006 | ::close( d->proc->socketStdout ); | 1006 | ::close( d->proc->socketStdout ); |
1007 | d->proc->socketStdout = 0; | 1007 | d->proc->socketStdout = 0; |
1008 | return; | 1008 | return; |
1009 | } else if ( fd == d->proc->socketStderr ) { | 1009 | } else if ( fd == d->proc->socketStderr ) { |
1010 | #if defined(QT_QPROCESS_DEBUG) | 1010 | #if defined(QT_QPROCESS_DEBUG) |
1011 | odebug << "QProcess::socketRead(): stderr (" << fd << ") closed" << oendl; | 1011 | odebug << "QProcess::socketRead(): stderr (" << fd << ") closed" << oendl; |
1012 | #endif | 1012 | #endif |
1013 | d->notifierStderr->setEnabled( FALSE ); | 1013 | d->notifierStderr->setEnabled( FALSE ); |
1014 | delete d->notifierStderr; | 1014 | delete d->notifierStderr; |
1015 | d->notifierStderr = 0; | 1015 | d->notifierStderr = 0; |
1016 | ::close( d->proc->socketStderr ); | 1016 | ::close( d->proc->socketStderr ); |
1017 | d->proc->socketStderr = 0; | 1017 | d->proc->socketStderr = 0; |
1018 | return; | 1018 | return; |
1019 | } | 1019 | } |
1020 | } | 1020 | } |
1021 | // read all data that is available | 1021 | // read all data that is available |
1022 | while ( n == bufsize ) { | 1022 | while ( n == bufsize ) { |
1023 | oldSize = buffer->size(); | 1023 | oldSize = buffer->size(); |
1024 | buffer->resize( oldSize + bufsize ); | 1024 | buffer->resize( oldSize + bufsize ); |
1025 | n = ::read( fd, buffer->data()+oldSize, bufsize ); | 1025 | n = ::read( fd, buffer->data()+oldSize, bufsize ); |
1026 | if ( n > 0 ) | 1026 | if ( n > 0 ) |
1027 | buffer->resize( oldSize + n ); | 1027 | buffer->resize( oldSize + n ); |
1028 | else | 1028 | else |
1029 | buffer->resize( oldSize ); | 1029 | buffer->resize( oldSize ); |
1030 | } | 1030 | } |
1031 | 1031 | ||
1032 | d->socketReadCalled = TRUE; | 1032 | d->socketReadCalled = TRUE; |
1033 | if ( fd == d->proc->socketStdout ) { | 1033 | if ( fd == d->proc->socketStdout ) { |
1034 | #if defined(QT_QPROCESS_DEBUG) | 1034 | #if defined(QT_QPROCESS_DEBUG) |
1035 | qDebug( "QProcess::socketRead(): %d bytes read from stdout (%d)", | 1035 | qDebug( "QProcess::socketRead(): %d bytes read from stdout (%d)", |
1036 | buffer->size()-oldSize, fd ); | 1036 | buffer->size()-oldSize, fd ); |
1037 | #endif | 1037 | #endif |
1038 | emit readyReadStdout(); | 1038 | emit readyReadStdout(); |
1039 | } else if ( fd == d->proc->socketStderr ) { | 1039 | } else if ( fd == d->proc->socketStderr ) { |
1040 | #if defined(QT_QPROCESS_DEBUG) | 1040 | #if defined(QT_QPROCESS_DEBUG) |
1041 | qDebug( "QProcess::socketRead(): %d bytes read from stderr (%d)", | 1041 | qDebug( "QProcess::socketRead(): %d bytes read from stderr (%d)", |
1042 | buffer->size()-oldSize, fd ); | 1042 | buffer->size()-oldSize, fd ); |
1043 | #endif | 1043 | #endif |
1044 | emit readyReadStderr(); | 1044 | emit readyReadStderr(); |
1045 | } | 1045 | } |
1046 | d->socketReadCalled = FALSE; | 1046 | d->socketReadCalled = FALSE; |
1047 | } | 1047 | } |
1048 | 1048 | ||
1049 | 1049 | ||
1050 | /* | 1050 | /* |
1051 | This private slot is called when the process tries to read data from standard | 1051 | This private slot is called when the process tries to read data from standard |
1052 | input. | 1052 | input. |
1053 | */ | 1053 | */ |
1054 | void QProcess::socketWrite( int fd ) | 1054 | void QProcess::socketWrite( int fd ) |
1055 | { | 1055 | { |
1056 | if ( fd != d->proc->socketStdin || d->proc->socketStdin == 0 ) | 1056 | if ( fd != d->proc->socketStdin || d->proc->socketStdin == 0 ) |
1057 | return; | 1057 | return; |
1058 | if ( d->stdinBuf.isEmpty() ) { | 1058 | if ( d->stdinBuf.isEmpty() ) { |
1059 | d->notifierStdin->setEnabled( FALSE ); | 1059 | d->notifierStdin->setEnabled( FALSE ); |
1060 | return; | 1060 | return; |
1061 | } | 1061 | } |
1062 | #if defined(QT_QPROCESS_DEBUG) | 1062 | #if defined(QT_QPROCESS_DEBUG) |
1063 | odebug << "QProcess::socketWrite(): write to stdin (" << fd << ")" << oendl; | 1063 | odebug << "QProcess::socketWrite(): write to stdin (" << fd << ")" << oendl; |
1064 | #endif | 1064 | #endif |
1065 | ssize_t ret = ::write( fd, | 1065 | ssize_t ret = ::write( fd, |
1066 | d->stdinBuf.head()->data() + d->stdinBufRead, | 1066 | d->stdinBuf.head()->data() + d->stdinBufRead, |
1067 | d->stdinBuf.head()->size() - d->stdinBufRead ); | 1067 | d->stdinBuf.head()->size() - d->stdinBufRead ); |
1068 | if ( ret > 0 ) | 1068 | if ( ret > 0 ) |
1069 | d->stdinBufRead += ret; | 1069 | d->stdinBufRead += ret; |
1070 | if ( d->stdinBufRead == (ssize_t)d->stdinBuf.head()->size() ) { | 1070 | if ( d->stdinBufRead == (ssize_t)d->stdinBuf.head()->size() ) { |
1071 | d->stdinBufRead = 0; | 1071 | d->stdinBufRead = 0; |
1072 | delete d->stdinBuf.dequeue(); | 1072 | delete d->stdinBuf.dequeue(); |
1073 | if ( wroteToStdinConnected && d->stdinBuf.isEmpty() ) | 1073 | if ( wroteToStdinConnected && d->stdinBuf.isEmpty() ) |
1074 | emit wroteToStdin(); | 1074 | emit wroteToStdin(); |
1075 | socketWrite( fd ); | 1075 | socketWrite( fd ); |
1076 | } | 1076 | } |
1077 | } | 1077 | } |
1078 | 1078 | ||
1079 | /*! | 1079 | /*! |
1080 | \internal | 1080 | \internal |
1081 | Flushes standard input. This is useful if you want to use QProcess in a | 1081 | Flushes standard input. This is useful if you want to use QProcess in a |
1082 | synchronous manner. | 1082 | synchronous manner. |
1083 | 1083 | ||
1084 | This function should probably go into the public API. | 1084 | This function should probably go into the public API. |
1085 | */ | 1085 | */ |
1086 | void QProcess::flushStdin() | 1086 | void QProcess::flushStdin() |
1087 | { | 1087 | { |
1088 | socketWrite( d->proc->socketStdin ); | 1088 | socketWrite( d->proc->socketStdin ); |
1089 | } | 1089 | } |
1090 | 1090 | ||
1091 | /* | 1091 | /* |
1092 | This private slot is only used under Windows (but moc does not know about #if | 1092 | This private slot is only used under Windows (but moc does not know about #if |
1093 | defined()). | 1093 | defined()). |
1094 | */ | 1094 | */ |
1095 | void QProcess::timeout() | 1095 | void QProcess::timeout() |
1096 | { | 1096 | { |
1097 | } | 1097 | } |
1098 | 1098 | ||
1099 | 1099 | ||
1100 | /* | 1100 | /* |
1101 | This private function is used by connectNotify() and disconnectNotify() to | 1101 | This private function is used by connectNotify() and disconnectNotify() to |
1102 | change the value of ioRedirection (and related behaviour) | 1102 | change the value of ioRedirection (and related behaviour) |
1103 | */ | 1103 | */ |
1104 | void QProcess::setIoRedirection( bool value ) | 1104 | void QProcess::setIoRedirection( bool value ) |
1105 | { | 1105 | { |
1106 | ioRedirection = value; | 1106 | ioRedirection = value; |
1107 | if ( ioRedirection ) { | 1107 | if ( ioRedirection ) { |
1108 | if ( d->notifierStdout ) | 1108 | if ( d->notifierStdout ) |
1109 | d->notifierStdout->setEnabled( TRUE ); | 1109 | d->notifierStdout->setEnabled( TRUE ); |
1110 | if ( d->notifierStderr ) | 1110 | if ( d->notifierStderr ) |
1111 | d->notifierStderr->setEnabled( TRUE ); | 1111 | d->notifierStderr->setEnabled( TRUE ); |
1112 | } else { | 1112 | } else { |
1113 | if ( d->notifierStdout ) | 1113 | if ( d->notifierStdout ) |
1114 | d->notifierStdout->setEnabled( FALSE ); | 1114 | d->notifierStdout->setEnabled( FALSE ); |
1115 | if ( d->notifierStderr ) | 1115 | if ( d->notifierStderr ) |
1116 | d->notifierStderr->setEnabled( FALSE ); | 1116 | d->notifierStderr->setEnabled( FALSE ); |
1117 | } | 1117 | } |
1118 | } | 1118 | } |
1119 | 1119 | ||
1120 | /* | 1120 | /* |
1121 | This private function is used by connectNotify() and | 1121 | This private function is used by connectNotify() and |
1122 | disconnectNotify() to change the value of notifyOnExit (and related | 1122 | disconnectNotify() to change the value of notifyOnExit (and related |
1123 | behaviour) | 1123 | behaviour) |
1124 | */ | 1124 | */ |
1125 | void QProcess::setNotifyOnExit( bool value ) | 1125 | void QProcess::setNotifyOnExit( bool value ) |
1126 | { | 1126 | { |
1127 | notifyOnExit = value; | 1127 | notifyOnExit = value; |
1128 | } | 1128 | } |
1129 | 1129 | ||
1130 | /* | 1130 | /* |
1131 | This private function is used by connectNotify() and disconnectNotify() to | 1131 | This private function is used by connectNotify() and disconnectNotify() to |
1132 | change the value of wroteToStdinConnected (and related behaviour) | 1132 | change the value of wroteToStdinConnected (and related behaviour) |
1133 | */ | 1133 | */ |
1134 | void QProcess::setWroteStdinConnected( bool value ) | 1134 | void QProcess::setWroteStdinConnected( bool value ) |
1135 | { | 1135 | { |
1136 | wroteToStdinConnected = value; | 1136 | wroteToStdinConnected = value; |
1137 | } | 1137 | } |
1138 | 1138 | ||
1139 | /*! \enum QProcess::PID | 1139 | /*! \enum QProcess::PID |
1140 | \internal | 1140 | \internal |
1141 | */ | 1141 | */ |
1142 | /*! | 1142 | /*! |
1143 | Returns platform dependent information about the process. This can be used | 1143 | Returns platform dependent information about the process. This can be used |
1144 | together with platform specific system calls. | 1144 | together with platform specific system calls. |
1145 | 1145 | ||
1146 | Under Unix the return value is the PID of the process, or -1 if no process is | 1146 | Under Unix the return value is the PID of the process, or -1 if no process is |
1147 | belonging to this object. | 1147 | belonging to this object. |
1148 | 1148 | ||
1149 | Under Windows it is a pointer to the \c PROCESS_INFORMATION struct, or 0 if | 1149 | Under Windows it is a pointer to the \c PROCESS_INFORMATION struct, or 0 if |
1150 | no process is belonging to this object. | 1150 | no process is belonging to this object. |
1151 | */ | 1151 | */ |
1152 | QProcess::PID QProcess::processIdentifier() | 1152 | QProcess::PID QProcess::processIdentifier() |
1153 | { | 1153 | { |
1154 | if ( d->proc == 0 ) | 1154 | if ( d->proc == 0 ) |
1155 | return -1; | 1155 | return -1; |
1156 | return d->proc->pid; | 1156 | return d->proc->pid; |
1157 | } | 1157 | } |
1158 | 1158 | ||
1159 | int QProcess::priority() const | 1159 | int QProcess::priority() const |
1160 | { | 1160 | { |
1161 | if ( d->proc ) | 1161 | if ( d->proc ) |
1162 | return getpriority(PRIO_PROCESS,d->proc->pid); | 1162 | return getpriority(PRIO_PROCESS,d->proc->pid); |
1163 | return 0; | 1163 | return 0; |
1164 | } | 1164 | } |
1165 | 1165 | ||
1166 | void QProcess::setPriority(int p) | 1166 | void QProcess::setPriority(int p) |
1167 | { | 1167 | { |
1168 | if ( d->proc ) | 1168 | if ( d->proc ) |
1169 | setpriority(PRIO_PROCESS,d->proc->pid,p); | 1169 | setpriority(PRIO_PROCESS,d->proc->pid,p); |
1170 | } | 1170 | } |
1171 | 1171 | ||
1172 | 1172 | ||
1173 | #endif // QT_NO_PROCESS | 1173 | #endif // QT_NO_PROCESS |