1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the QtCore module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | //#define QPROCESS_DEBUG |
43 | #include "qdebug.h" |
44 | |
45 | #ifndef QT_NO_PROCESS |
46 | |
47 | #if defined QPROCESS_DEBUG |
48 | #include "qstring.h" |
49 | #include <ctype.h> |
50 | |
51 | /* |
52 | Returns a human readable representation of the first \a len |
53 | characters in \a data. |
54 | */ |
55 | QT_BEGIN_NAMESPACE |
56 | static QByteArray qt_prettyDebug(const char *data, int len, int maxSize) |
57 | { |
58 | if (!data) return "(null)" ; |
59 | QByteArray out; |
60 | for (int i = 0; i < len; ++i) { |
61 | char c = data[i]; |
62 | if (isprint(c)) { |
63 | out += c; |
64 | } else switch (c) { |
65 | case '\n': out += "\\n" ; break; |
66 | case '\r': out += "\\r" ; break; |
67 | case '\t': out += "\\t" ; break; |
68 | default: |
69 | QString tmp; |
70 | tmp.sprintf("\\%o" , c); |
71 | out += tmp.toLatin1(); |
72 | } |
73 | } |
74 | |
75 | if (len < maxSize) |
76 | out += "..." ; |
77 | |
78 | return out; |
79 | } |
80 | QT_END_NAMESPACE |
81 | #endif |
82 | |
83 | #include "qplatformdefs.h" |
84 | |
85 | #include "qprocess.h" |
86 | #include "qprocess_p.h" |
87 | #include "private/qcore_unix_p.h" |
88 | |
89 | #ifdef Q_OS_MAC |
90 | #include <private/qcore_mac_p.h> |
91 | #endif |
92 | |
93 | #include <private/qcoreapplication_p.h> |
94 | #include <private/qthread_p.h> |
95 | #include <qfile.h> |
96 | #include <qfileinfo.h> |
97 | #include <qlist.h> |
98 | #include <qhash.h> |
99 | #include <qmutex.h> |
100 | #include <qsemaphore.h> |
101 | #include <qsocketnotifier.h> |
102 | #include <qthread.h> |
103 | #include <qelapsedtimer.h> |
104 | |
105 | #include <errno.h> |
106 | #include <stdlib.h> |
107 | #include <string.h> |
108 | #ifdef Q_OS_QNX |
109 | #include "qvarlengtharray.h" |
110 | |
111 | #include <spawn.h> |
112 | #include <sys/neutrino.h> |
113 | #endif |
114 | |
115 | |
116 | QT_BEGIN_NAMESPACE |
117 | |
118 | // POSIX requires PIPE_BUF to be 512 or larger |
119 | // so we will use 512 |
120 | static const int errorBufferMax = 512; |
121 | |
122 | #ifdef Q_OS_INTEGRITY |
123 | static inline char *strdup(const char *data) |
124 | { |
125 | return qstrdup(data); |
126 | } |
127 | #endif |
128 | |
129 | static int qt_qprocess_deadChild_pipe[2]; |
130 | static struct sigaction qt_sa_old_sigchld_handler; |
131 | static void qt_sa_sigchld_sigaction(int signum, siginfo_t *info, void *context) |
132 | { |
133 | // *Never* use the info or contect variables in this function |
134 | // (except for passing them to the next signal in the chain). |
135 | // We cannot be sure if another library or if the application |
136 | // installed a signal handler for SIGCHLD without SA_SIGINFO |
137 | // and fails to pass the arguments to us. If they do that, |
138 | // these arguments contain garbage and we'd most likely crash. |
139 | |
140 | qt_safe_write(qt_qprocess_deadChild_pipe[1], "" , 1); |
141 | #if defined (QPROCESS_DEBUG) |
142 | fprintf(stderr, "*** SIGCHLD\n" ); |
143 | #endif |
144 | |
145 | // load as volatile |
146 | volatile struct sigaction *vsa = &qt_sa_old_sigchld_handler; |
147 | |
148 | if (qt_sa_old_sigchld_handler.sa_flags & SA_SIGINFO) { |
149 | void (*oldAction)(int, siginfo_t *, void *) = vsa->sa_sigaction; |
150 | |
151 | if (oldAction) |
152 | oldAction(signum, info, context); |
153 | } else { |
154 | void (*oldAction)(int) = vsa->sa_handler; |
155 | |
156 | if (oldAction && oldAction != SIG_IGN) |
157 | oldAction(signum); |
158 | } |
159 | } |
160 | |
161 | static inline void add_fd(int &nfds, int fd, fd_set *fdset) |
162 | { |
163 | FD_SET(fd, fdset); |
164 | if ((fd) > nfds) |
165 | nfds = fd; |
166 | } |
167 | |
168 | struct QProcessInfo { |
169 | QProcess *process; |
170 | int deathPipe; |
171 | int exitResult; |
172 | pid_t pid; |
173 | int serialNumber; |
174 | }; |
175 | |
176 | class QProcessManager : public QThread |
177 | { |
178 | Q_OBJECT |
179 | public: |
180 | QProcessManager(); |
181 | ~QProcessManager(); |
182 | |
183 | void run(); |
184 | void catchDeadChildren(); |
185 | void add(pid_t pid, QProcess *process); |
186 | void remove(QProcess *process); |
187 | void lock(); |
188 | void unlock(); |
189 | |
190 | private: |
191 | QMutex mutex; |
192 | QHash<int, QProcessInfo *> children; |
193 | }; |
194 | |
195 | |
196 | Q_GLOBAL_STATIC(QMutex, processManagerGlobalMutex) |
197 | |
198 | static QProcessManager *processManager() { |
199 | // The constructor of QProcessManager should be called only once |
200 | // so we cannot use Q_GLOBAL_STATIC directly for QProcessManager |
201 | QMutex *mutex = processManagerGlobalMutex(); |
202 | QMutexLocker locker(mutex); |
203 | static QProcessManager processManager; |
204 | return &processManager; |
205 | } |
206 | |
207 | QProcessManager::QProcessManager() |
208 | { |
209 | #if defined (QPROCESS_DEBUG) |
210 | qDebug() << "QProcessManager::QProcessManager()" ; |
211 | #endif |
212 | // initialize the dead child pipe and make it non-blocking. in the |
213 | // extremely unlikely event that the pipe fills up, we do not under any |
214 | // circumstances want to block. |
215 | qt_safe_pipe(qt_qprocess_deadChild_pipe, O_NONBLOCK); |
216 | |
217 | // set up the SIGCHLD handler, which writes a single byte to the dead |
218 | // child pipe every time a child dies. |
219 | |
220 | struct sigaction action; |
221 | // use the old handler as template, i.e., preserve the signal mask |
222 | // otherwise the original signal handler might be interrupted although it |
223 | // was marked to never be interrupted |
224 | ::sigaction(SIGCHLD, NULL, &action); |
225 | action.sa_sigaction = qt_sa_sigchld_sigaction; |
226 | // set the SA_SIGINFO flag such that we can use the three argument handler |
227 | // function |
228 | action.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; |
229 | ::sigaction(SIGCHLD, &action, &qt_sa_old_sigchld_handler); |
230 | } |
231 | |
232 | QProcessManager::~QProcessManager() |
233 | { |
234 | // notify the thread that we're shutting down. |
235 | qt_safe_write(qt_qprocess_deadChild_pipe[1], "@" , 1); |
236 | qt_safe_close(qt_qprocess_deadChild_pipe[1]); |
237 | wait(); |
238 | |
239 | // on certain unixes, closing the reading end of the pipe will cause |
240 | // select in run() to block forever, rather than return with EBADF. |
241 | qt_safe_close(qt_qprocess_deadChild_pipe[0]); |
242 | |
243 | qt_qprocess_deadChild_pipe[0] = -1; |
244 | qt_qprocess_deadChild_pipe[1] = -1; |
245 | |
246 | qDeleteAll(children.values()); |
247 | children.clear(); |
248 | |
249 | struct sigaction currentAction; |
250 | ::sigaction(SIGCHLD, 0, ¤tAction); |
251 | if (currentAction.sa_sigaction == qt_sa_sigchld_sigaction) { |
252 | ::sigaction(SIGCHLD, &qt_sa_old_sigchld_handler, 0); |
253 | } |
254 | } |
255 | |
256 | void QProcessManager::run() |
257 | { |
258 | forever { |
259 | fd_set readset; |
260 | FD_ZERO(&readset); |
261 | FD_SET(qt_qprocess_deadChild_pipe[0], &readset); |
262 | |
263 | #if defined (QPROCESS_DEBUG) |
264 | qDebug() << "QProcessManager::run() waiting for children to die" ; |
265 | #endif |
266 | |
267 | // block forever, or until activity is detected on the dead child |
268 | // pipe. the only other peers are the SIGCHLD signal handler, and the |
269 | // QProcessManager destructor. |
270 | int nselect = select(qt_qprocess_deadChild_pipe[0] + 1, &readset, 0, 0, 0); |
271 | if (nselect < 0) { |
272 | if (errno == EINTR) |
273 | continue; |
274 | break; |
275 | } |
276 | |
277 | // empty only one byte from the pipe, even though several SIGCHLD |
278 | // signals may have been delivered in the meantime, to avoid race |
279 | // conditions. |
280 | char c; |
281 | if (qt_safe_read(qt_qprocess_deadChild_pipe[0], &c, 1) < 0 || c == '@') |
282 | break; |
283 | |
284 | // catch any and all children that we can. |
285 | catchDeadChildren(); |
286 | } |
287 | } |
288 | |
289 | void QProcessManager::catchDeadChildren() |
290 | { |
291 | QMutexLocker locker(&mutex); |
292 | |
293 | // try to catch all children whose pid we have registered, and whose |
294 | // deathPipe is still valid (i.e, we have not already notified it). |
295 | QHash<int, QProcessInfo *>::Iterator it = children.begin(); |
296 | while (it != children.end()) { |
297 | // notify all children that they may have died. they need to run |
298 | // waitpid() in their own thread. |
299 | QProcessInfo *info = it.value(); |
300 | qt_safe_write(info->deathPipe, "" , 1); |
301 | |
302 | #if defined (QPROCESS_DEBUG) |
303 | qDebug() << "QProcessManager::run() sending death notice to" << info->process; |
304 | #endif |
305 | ++it; |
306 | } |
307 | } |
308 | |
309 | static QBasicAtomicInt idCounter = Q_BASIC_ATOMIC_INITIALIZER(1); |
310 | |
311 | void QProcessManager::add(pid_t pid, QProcess *process) |
312 | { |
313 | #if defined (QPROCESS_DEBUG) |
314 | qDebug() << "QProcessManager::add() adding pid" << pid << "process" << process; |
315 | #endif |
316 | |
317 | // insert a new info structure for this process |
318 | QProcessInfo *info = new QProcessInfo; |
319 | info->process = process; |
320 | info->deathPipe = process->d_func()->deathPipe[1]; |
321 | info->exitResult = 0; |
322 | info->pid = pid; |
323 | |
324 | int serial = idCounter.fetchAndAddRelaxed(1); |
325 | process->d_func()->serial = serial; |
326 | children.insert(serial, info); |
327 | } |
328 | |
329 | void QProcessManager::remove(QProcess *process) |
330 | { |
331 | QMutexLocker locker(&mutex); |
332 | |
333 | int serial = process->d_func()->serial; |
334 | QProcessInfo *info = children.take(serial); |
335 | #if defined (QPROCESS_DEBUG) |
336 | if (info) |
337 | qDebug() << "QProcessManager::remove() removing pid" << info->pid << "process" << info->process; |
338 | #endif |
339 | delete info; |
340 | } |
341 | |
342 | void QProcessManager::lock() |
343 | { |
344 | mutex.lock(); |
345 | } |
346 | |
347 | void QProcessManager::unlock() |
348 | { |
349 | mutex.unlock(); |
350 | } |
351 | |
352 | static int qt_create_pipe(int *pipe) |
353 | { |
354 | if (pipe[0] != -1) |
355 | qt_safe_close(pipe[0]); |
356 | if (pipe[1] != -1) |
357 | qt_safe_close(pipe[1]); |
358 | int pipe_ret = qt_safe_pipe(pipe); |
359 | if (pipe_ret != 0) { |
360 | qWarning("QProcessPrivate::createPipe: Cannot create pipe %p: %s" , |
361 | pipe, qPrintable(qt_error_string(errno))); |
362 | } |
363 | return pipe_ret; |
364 | } |
365 | |
366 | void QProcessPrivate::destroyPipe(int *pipe) |
367 | { |
368 | if (pipe[1] != -1) { |
369 | qt_safe_close(pipe[1]); |
370 | pipe[1] = -1; |
371 | } |
372 | if (pipe[0] != -1) { |
373 | qt_safe_close(pipe[0]); |
374 | pipe[0] = -1; |
375 | } |
376 | } |
377 | |
378 | /* |
379 | Create the pipes to a QProcessPrivate::Channel. |
380 | |
381 | This function must be called in order: stdin, stdout, stderr |
382 | */ |
383 | bool QProcessPrivate::createChannel(Channel &channel) |
384 | { |
385 | Q_Q(QProcess); |
386 | |
387 | if (&channel == &stderrChannel && processChannelMode == QProcess::MergedChannels) { |
388 | channel.pipe[0] = -1; |
389 | channel.pipe[1] = -1; |
390 | return true; |
391 | } |
392 | |
393 | if (channel.type == Channel::Normal) { |
394 | // we're piping this channel to our own process |
395 | if (qt_create_pipe(channel.pipe) != 0) |
396 | return false; |
397 | |
398 | // create the socket notifiers |
399 | if (threadData->eventDispatcher) { |
400 | if (&channel == &stdinChannel) { |
401 | channel.notifier = new QSocketNotifier(channel.pipe[1], |
402 | QSocketNotifier::Write, q); |
403 | channel.notifier->setEnabled(false); |
404 | QObject::connect(channel.notifier, SIGNAL(activated(int)), |
405 | q, SLOT(_q_canWrite())); |
406 | } else { |
407 | channel.notifier = new QSocketNotifier(channel.pipe[0], |
408 | QSocketNotifier::Read, q); |
409 | const char *receiver; |
410 | if (&channel == &stdoutChannel) |
411 | receiver = SLOT(_q_canReadStandardOutput()); |
412 | else |
413 | receiver = SLOT(_q_canReadStandardError()); |
414 | QObject::connect(channel.notifier, SIGNAL(activated(int)), |
415 | q, receiver); |
416 | } |
417 | } |
418 | |
419 | return true; |
420 | } else if (channel.type == Channel::Redirect) { |
421 | // we're redirecting the channel to/from a file |
422 | QByteArray fname = QFile::encodeName(channel.file); |
423 | |
424 | if (&channel == &stdinChannel) { |
425 | // try to open in read-only mode |
426 | channel.pipe[1] = -1; |
427 | if ( (channel.pipe[0] = qt_safe_open(fname, O_RDONLY)) != -1) |
428 | return true; // success |
429 | |
430 | q->setErrorString(QProcess::tr("Could not open input redirection for reading" )); |
431 | } else { |
432 | int mode = O_WRONLY | O_CREAT; |
433 | if (channel.append) |
434 | mode |= O_APPEND; |
435 | else |
436 | mode |= O_TRUNC; |
437 | |
438 | channel.pipe[0] = -1; |
439 | if ( (channel.pipe[1] = qt_safe_open(fname, mode, 0666)) != -1) |
440 | return true; // success |
441 | |
442 | q->setErrorString(QProcess::tr("Could not open output redirection for writing" )); |
443 | } |
444 | |
445 | // could not open file |
446 | processError = QProcess::FailedToStart; |
447 | emit q->error(processError); |
448 | cleanup(); |
449 | return false; |
450 | } else { |
451 | Q_ASSERT_X(channel.process, "QProcess::start" , "Internal error" ); |
452 | |
453 | Channel *source; |
454 | Channel *sink; |
455 | |
456 | if (channel.type == Channel::PipeSource) { |
457 | // we are the source |
458 | source = &channel; |
459 | sink = &channel.process->stdinChannel; |
460 | |
461 | Q_ASSERT(source == &stdoutChannel); |
462 | Q_ASSERT(sink->process == this && sink->type == Channel::PipeSink); |
463 | } else { |
464 | // we are the sink; |
465 | source = &channel.process->stdoutChannel; |
466 | sink = &channel; |
467 | |
468 | Q_ASSERT(sink == &stdinChannel); |
469 | Q_ASSERT(source->process == this && source->type == Channel::PipeSource); |
470 | } |
471 | |
472 | if (source->pipe[1] != INVALID_Q_PIPE || sink->pipe[0] != INVALID_Q_PIPE) { |
473 | // already created, do nothing |
474 | return true; |
475 | } else { |
476 | Q_ASSERT(source->pipe[0] == INVALID_Q_PIPE && source->pipe[1] == INVALID_Q_PIPE); |
477 | Q_ASSERT(sink->pipe[0] == INVALID_Q_PIPE && sink->pipe[1] == INVALID_Q_PIPE); |
478 | |
479 | Q_PIPE pipe[2] = { -1, -1 }; |
480 | if (qt_create_pipe(pipe) != 0) |
481 | return false; |
482 | sink->pipe[0] = pipe[0]; |
483 | source->pipe[1] = pipe[1]; |
484 | |
485 | return true; |
486 | } |
487 | } |
488 | } |
489 | |
490 | QT_BEGIN_INCLUDE_NAMESPACE |
491 | #if defined(Q_OS_MAC) && !defined(Q_OS_IOS) |
492 | # include <crt_externs.h> |
493 | # define environ (*_NSGetEnviron()) |
494 | #else |
495 | extern char **environ; |
496 | #endif |
497 | QT_END_INCLUDE_NAMESPACE |
498 | |
499 | QProcessEnvironment QProcessEnvironment::systemEnvironment() |
500 | { |
501 | QProcessEnvironment env; |
502 | #if !defined(Q_OS_IOS) |
503 | const char *entry; |
504 | for (int count = 0; (entry = environ[count]); ++count) { |
505 | const char *equal = strchr(entry, '='); |
506 | if (!equal) |
507 | continue; |
508 | |
509 | QByteArray name(entry, equal - entry); |
510 | QByteArray value(equal + 1); |
511 | env.d->hash.insert(QProcessEnvironmentPrivate::Key(name), |
512 | QProcessEnvironmentPrivate::Value(value)); |
513 | } |
514 | #endif |
515 | return env; |
516 | } |
517 | |
518 | static char **_q_dupEnvironment(const QProcessEnvironmentPrivate::Hash &environment, int *envc) |
519 | { |
520 | *envc = 0; |
521 | if (environment.isEmpty()) |
522 | return 0; |
523 | |
524 | // if LD_LIBRARY_PATH exists in the current environment, but |
525 | // not in the environment list passed by the programmer, then |
526 | // copy it over. |
527 | #if defined(Q_OS_MAC) |
528 | static const char libraryPath[] = "DYLD_LIBRARY_PATH" ; |
529 | #else |
530 | static const char libraryPath[] = "LD_LIBRARY_PATH" ; |
531 | #endif |
532 | const QByteArray envLibraryPath = qgetenv(libraryPath); |
533 | bool needToAddLibraryPath = !envLibraryPath.isEmpty() && |
534 | !environment.contains(QProcessEnvironmentPrivate::Key(QByteArray(libraryPath))); |
535 | |
536 | char **envp = new char *[environment.count() + 2]; |
537 | envp[environment.count()] = 0; |
538 | envp[environment.count() + 1] = 0; |
539 | |
540 | QProcessEnvironmentPrivate::Hash::ConstIterator it = environment.constBegin(); |
541 | const QProcessEnvironmentPrivate::Hash::ConstIterator end = environment.constEnd(); |
542 | for ( ; it != end; ++it) { |
543 | QByteArray key = it.key().key; |
544 | QByteArray value = it.value().bytes(); |
545 | key.reserve(key.length() + 1 + value.length()); |
546 | key.append('='); |
547 | key.append(value); |
548 | |
549 | envp[(*envc)++] = ::strdup(key.constData()); |
550 | } |
551 | |
552 | if (needToAddLibraryPath) |
553 | envp[(*envc)++] = ::strdup(QByteArray(QByteArray(libraryPath) + '=' + |
554 | envLibraryPath).constData()); |
555 | return envp; |
556 | } |
557 | |
558 | #ifdef Q_OS_MAC |
559 | Q_GLOBAL_STATIC(QMutex, cfbundleMutex); |
560 | #endif |
561 | |
562 | void QProcessPrivate::startProcess() |
563 | { |
564 | Q_Q(QProcess); |
565 | |
566 | #if defined (QPROCESS_DEBUG) |
567 | qDebug("QProcessPrivate::startProcess()" ); |
568 | #endif |
569 | |
570 | processManager()->start(); |
571 | |
572 | // Initialize pipes |
573 | if (!createChannel(stdinChannel) || |
574 | !createChannel(stdoutChannel) || |
575 | !createChannel(stderrChannel) || |
576 | qt_create_pipe(childStartedPipe) != 0 || |
577 | qt_create_pipe(deathPipe) != 0) { |
578 | processError = QProcess::FailedToStart; |
579 | q->setErrorString(qt_error_string(errno)); |
580 | emit q->error(processError); |
581 | cleanup(); |
582 | return; |
583 | } |
584 | |
585 | if (threadData->eventDispatcher) { |
586 | startupSocketNotifier = new QSocketNotifier(childStartedPipe[0], |
587 | QSocketNotifier::Read, q); |
588 | QObject::connect(startupSocketNotifier, SIGNAL(activated(int)), |
589 | q, SLOT(_q_startupNotification())); |
590 | deathNotifier = new QSocketNotifier(deathPipe[0], |
591 | QSocketNotifier::Read, q); |
592 | QObject::connect(deathNotifier, SIGNAL(activated(int)), |
593 | q, SLOT(_q_processDied())); |
594 | } |
595 | |
596 | // Start the process (platform dependent) |
597 | q->setProcessState(QProcess::Starting); |
598 | |
599 | // Create argument list with right number of elements, and set the final |
600 | // one to 0. |
601 | char **argv = new char *[arguments.count() + 2]; |
602 | argv[arguments.count() + 1] = 0; |
603 | |
604 | // Encode the program name. |
605 | QByteArray encodedProgramName = QFile::encodeName(program); |
606 | #ifdef Q_OS_MAC |
607 | // allow invoking of .app bundles on the Mac. |
608 | QFileInfo fileInfo(QString::fromUtf8(encodedProgramName.constData())); |
609 | if (encodedProgramName.endsWith(".app" ) && fileInfo.isDir()) { |
610 | QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, |
611 | QCFString(fileInfo.absoluteFilePath()), |
612 | kCFURLPOSIXPathStyle, true); |
613 | { |
614 | // CFBundle is not reentrant, since CFBundleCreate might return a reference |
615 | // to a cached bundle object. Protect the bundle calls with a mutex lock. |
616 | QMutexLocker lock(cfbundleMutex()); |
617 | QCFType<CFBundleRef> bundle = CFBundleCreate(0, url); |
618 | url = CFBundleCopyExecutableURL(bundle); |
619 | } |
620 | if (url) { |
621 | QCFString str = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); |
622 | encodedProgramName += "/Contents/MacOS/" + static_cast<QString>(str).toUtf8(); |
623 | } |
624 | } |
625 | #endif |
626 | |
627 | // Add the program name to the argument list. |
628 | char *dupProgramName = ::strdup(encodedProgramName.constData()); |
629 | argv[0] = dupProgramName; |
630 | |
631 | // Add every argument to the list |
632 | for (int i = 0; i < arguments.count(); ++i) { |
633 | QString arg = arguments.at(i); |
634 | #ifdef Q_OS_MAC |
635 | // Mac OS X uses UTF8 for exec, regardless of the system locale. |
636 | argv[i + 1] = ::strdup(arg.toUtf8().constData()); |
637 | #else |
638 | argv[i + 1] = ::strdup(arg.toLocal8Bit().constData()); |
639 | #endif |
640 | } |
641 | |
642 | // Duplicate the environment. |
643 | int envc = 0; |
644 | char **envp = 0; |
645 | if (environment.d.constData()) { |
646 | QProcessEnvironmentPrivate::MutexLocker locker(environment.d); |
647 | envp = _q_dupEnvironment(environment.d.constData()->hash, &envc); |
648 | } |
649 | |
650 | // Encode the working directory if it's non-empty, otherwise just pass 0. |
651 | const char *workingDirPtr = 0; |
652 | QByteArray encodedWorkingDirectory; |
653 | if (!workingDirectory.isEmpty()) { |
654 | encodedWorkingDirectory = QFile::encodeName(workingDirectory); |
655 | workingDirPtr = encodedWorkingDirectory.constData(); |
656 | } |
657 | |
658 | // If the program does not specify a path, generate a list of possible |
659 | // locations for the binary using the PATH environment variable. |
660 | char **path = 0; |
661 | int pathc = 0; |
662 | if (!program.contains(QLatin1Char('/'))) { |
663 | const QString pathEnv = QString::fromLocal8Bit(::getenv("PATH" )); |
664 | if (!pathEnv.isEmpty()) { |
665 | QStringList pathEntries = pathEnv.split(QLatin1Char(':'), QString::SkipEmptyParts); |
666 | if (!pathEntries.isEmpty()) { |
667 | pathc = pathEntries.size(); |
668 | path = new char *[pathc + 1]; |
669 | path[pathc] = 0; |
670 | |
671 | for (int k = 0; k < pathEntries.size(); ++k) { |
672 | QByteArray tmp = QFile::encodeName(pathEntries.at(k)); |
673 | if (!tmp.endsWith('/')) tmp += '/'; |
674 | tmp += encodedProgramName; |
675 | path[k] = ::strdup(tmp.constData()); |
676 | } |
677 | } |
678 | } |
679 | } |
680 | |
681 | // Start the process manager, and fork off the child process. |
682 | processManager()->lock(); |
683 | #if defined(Q_OS_QNX) |
684 | pid_t childPid = spawnChild(workingDirPtr, argv, envp); |
685 | #else |
686 | pid_t childPid = fork(); |
687 | int lastForkErrno = errno; |
688 | #endif |
689 | if (childPid != 0) { |
690 | // Clean up duplicated memory. |
691 | free(dupProgramName); |
692 | for (int i = 1; i <= arguments.count(); ++i) |
693 | free(argv[i]); |
694 | for (int i = 0; i < envc; ++i) |
695 | free(envp[i]); |
696 | for (int i = 0; i < pathc; ++i) |
697 | free(path[i]); |
698 | delete [] argv; |
699 | delete [] envp; |
700 | delete [] path; |
701 | } |
702 | |
703 | // This is not a valid check under QNX, because the semantics are |
704 | // different. While under other platforms where fork() may succeed and exec() can still fail, |
705 | // causing the childPid to hold a valid value (and thus evaluating the |
706 | // following if to false), and then signaling the error via |
707 | // childStartedPipe, under QNX on the other hand, spawn() return value will be assigned |
708 | // to childPid (which will be -1 in case of failure). This will force |
709 | // QProcess to cleanup, instead of signaling the error via |
710 | // childStartedPipe. Since it will invalidade the pipes, functions like |
711 | // QProcess::waitForStarted() will fail, for childStartedPipe will be |
712 | // '-1' and mess with the select() calls. |
713 | #if !defined(Q_OS_QNX) |
714 | if (childPid < 0) { |
715 | // Cleanup, report error and return |
716 | #if defined (QPROCESS_DEBUG) |
717 | qDebug("fork() failed: %s" , qPrintable(qt_error_string(lastForkErrno))); |
718 | #endif |
719 | processManager()->unlock(); |
720 | q->setProcessState(QProcess::NotRunning); |
721 | processError = QProcess::FailedToStart; |
722 | q->setErrorString(QProcess::tr("Resource error (fork failure): %1" ).arg(qt_error_string(lastForkErrno))); |
723 | emit q->error(processError); |
724 | cleanup(); |
725 | return; |
726 | } |
727 | |
728 | // Start the child. |
729 | if (childPid == 0) { |
730 | execChild(workingDirPtr, path, argv, envp); |
731 | ::_exit(-1); |
732 | } |
733 | #endif |
734 | |
735 | // Register the child. In the mean time, we can get a SIGCHLD, so we need |
736 | // to keep the lock held to avoid a race to catch the child. |
737 | processManager()->add(childPid, q); |
738 | pid = Q_PID(childPid); |
739 | processManager()->unlock(); |
740 | |
741 | // parent |
742 | // close the ends we don't use and make all pipes non-blocking |
743 | ::fcntl(deathPipe[0], F_SETFL, ::fcntl(deathPipe[0], F_GETFL) | O_NONBLOCK); |
744 | qt_safe_close(childStartedPipe[1]); |
745 | childStartedPipe[1] = -1; |
746 | |
747 | if (stdinChannel.pipe[0] != -1) { |
748 | qt_safe_close(stdinChannel.pipe[0]); |
749 | stdinChannel.pipe[0] = -1; |
750 | } |
751 | if (stdinChannel.pipe[1] != -1) |
752 | ::fcntl(stdinChannel.pipe[1], F_SETFL, ::fcntl(stdinChannel.pipe[1], F_GETFL) | O_NONBLOCK); |
753 | |
754 | if (stdoutChannel.pipe[1] != -1) { |
755 | qt_safe_close(stdoutChannel.pipe[1]); |
756 | stdoutChannel.pipe[1] = -1; |
757 | } |
758 | if (stdoutChannel.pipe[0] != -1) |
759 | ::fcntl(stdoutChannel.pipe[0], F_SETFL, ::fcntl(stdoutChannel.pipe[0], F_GETFL) | O_NONBLOCK); |
760 | |
761 | if (stderrChannel.pipe[1] != -1) { |
762 | qt_safe_close(stderrChannel.pipe[1]); |
763 | stderrChannel.pipe[1] = -1; |
764 | } |
765 | if (stderrChannel.pipe[0] != -1) |
766 | ::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK); |
767 | } |
768 | |
769 | #if !defined(Q_OS_QNX) |
770 | void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv, char **envp) |
771 | { |
772 | ::signal(SIGPIPE, SIG_DFL); // reset the signal that we ignored |
773 | |
774 | Q_Q(QProcess); |
775 | |
776 | // copy the stdin socket (without closing on exec) |
777 | qt_safe_dup2(stdinChannel.pipe[0], STDIN_FILENO, 0); |
778 | |
779 | // copy the stdout and stderr if asked to |
780 | if (processChannelMode != QProcess::ForwardedChannels) { |
781 | qt_safe_dup2(stdoutChannel.pipe[1], STDOUT_FILENO, 0); |
782 | |
783 | // merge stdout and stderr if asked to |
784 | if (processChannelMode == QProcess::MergedChannels) { |
785 | qt_safe_dup2(STDOUT_FILENO, STDERR_FILENO, 0); |
786 | } else { |
787 | qt_safe_dup2(stderrChannel.pipe[1], STDERR_FILENO, 0); |
788 | } |
789 | } |
790 | |
791 | // make sure this fd is closed if execvp() succeeds |
792 | qt_safe_close(childStartedPipe[0]); |
793 | |
794 | // enter the working directory |
795 | if (workingDir) |
796 | QT_CHDIR(workingDir); |
797 | |
798 | // this is a virtual call, and it base behavior is to do nothing. |
799 | q->setupChildProcess(); |
800 | |
801 | // execute the process |
802 | if (!envp) { |
803 | qt_safe_execvp(argv[0], argv); |
804 | } else { |
805 | if (path) { |
806 | char **arg = path; |
807 | while (*arg) { |
808 | argv[0] = *arg; |
809 | #if defined (QPROCESS_DEBUG) |
810 | fprintf(stderr, "QProcessPrivate::execChild() searching / starting %s\n" , argv[0]); |
811 | #endif |
812 | qt_safe_execve(argv[0], argv, envp); |
813 | ++arg; |
814 | } |
815 | } else { |
816 | #if defined (QPROCESS_DEBUG) |
817 | fprintf(stderr, "QProcessPrivate::execChild() starting %s\n" , argv[0]); |
818 | #endif |
819 | qt_safe_execve(argv[0], argv, envp); |
820 | } |
821 | } |
822 | |
823 | // notify failure |
824 | QString error = qt_error_string(errno); |
825 | #if defined (QPROCESS_DEBUG) |
826 | fprintf(stderr, "QProcessPrivate::execChild() failed (%s), notifying parent process\n" , qPrintable(error)); |
827 | #endif |
828 | qt_safe_write(childStartedPipe[1], error.data(), error.length() * sizeof(QChar)); |
829 | qt_safe_close(childStartedPipe[1]); |
830 | childStartedPipe[1] = -1; |
831 | } |
832 | |
833 | #endif //Q_OS_QNX |
834 | |
835 | bool QProcessPrivate::processStarted() |
836 | { |
837 | ushort buf[errorBufferMax]; |
838 | int i = qt_safe_read(childStartedPipe[0], &buf, sizeof buf); |
839 | if (startupSocketNotifier) { |
840 | startupSocketNotifier->setEnabled(false); |
841 | startupSocketNotifier->deleteLater(); |
842 | startupSocketNotifier = 0; |
843 | } |
844 | qt_safe_close(childStartedPipe[0]); |
845 | childStartedPipe[0] = -1; |
846 | |
847 | #if defined (QPROCESS_DEBUG) |
848 | qDebug("QProcessPrivate::processStarted() == %s" , i <= 0 ? "true" : "false" ); |
849 | #endif |
850 | |
851 | // did we read an error message? |
852 | if (i > 0) |
853 | q_func()->setErrorString(QString((const QChar *)buf, i / sizeof(QChar))); |
854 | |
855 | return i <= 0; |
856 | } |
857 | |
858 | #if defined(Q_OS_QNX) |
859 | static pid_t doSpawn(int fd_count, int fd_map[], char **argv, char **envp, |
860 | const char *workingDir, bool spawn_detached) |
861 | { |
862 | // A multi threaded QNX Process can't fork so we call spawn() instead. |
863 | |
864 | struct inheritance inherit; |
865 | memset(&inherit, 0, sizeof(inherit)); |
866 | inherit.flags |= SPAWN_SETSID; |
867 | inherit.flags |= SPAWN_CHECK_SCRIPT; |
868 | if (spawn_detached) |
869 | inherit.flags |= SPAWN_NOZOMBIE; |
870 | inherit.flags |= SPAWN_SETSIGDEF; |
871 | sigaddset(&inherit.sigdefault, SIGPIPE); // reset the signal that we ignored |
872 | |
873 | // enter the working directory |
874 | const char *oldWorkingDir = 0; |
875 | char buff[PATH_MAX + 1]; |
876 | |
877 | if (workingDir) { |
878 | //we need to freeze everyone in order to avoid race conditions with //chdir(). |
879 | if (ThreadCtl(_NTO_TCTL_THREADS_HOLD, 0) == -1) |
880 | qWarning("ThreadCtl(): cannot hold threads: %s" , qPrintable(qt_error_string(errno))); |
881 | |
882 | oldWorkingDir = QT_GETCWD(buff, PATH_MAX + 1); |
883 | QT_CHDIR(workingDir); |
884 | } |
885 | |
886 | pid_t childPid; |
887 | EINTR_LOOP(childPid, ::spawn(argv[0], fd_count, fd_map, &inherit, argv, envp)); |
888 | if (childPid == -1) { |
889 | inherit.flags |= SPAWN_SEARCH_PATH; |
890 | EINTR_LOOP(childPid, ::spawn(argv[0], fd_count, fd_map, &inherit, argv, envp)); |
891 | } |
892 | |
893 | if (oldWorkingDir) { |
894 | QT_CHDIR(oldWorkingDir); |
895 | |
896 | if (ThreadCtl(_NTO_TCTL_THREADS_CONT, 0) == -1) |
897 | qFatal("ThreadCtl(): cannot resume threads: %s" , qPrintable(qt_error_string(errno))); |
898 | } |
899 | |
900 | return childPid; |
901 | } |
902 | |
903 | pid_t QProcessPrivate::spawnChild(const char *workingDir, char **argv, char **envp) |
904 | { |
905 | // we need to manually fill in fd_map |
906 | // to inherit the file descriptors from |
907 | // the parent |
908 | const int fd_count = sysconf(_SC_OPEN_MAX); |
909 | QVarLengthArray<int, 1024> fd_map(fd_count); |
910 | |
911 | for (int i = 3; i < fd_count; ++i) { |
912 | // here we rely that fcntl returns -1 and |
913 | // sets errno to EBADF |
914 | const int flags = ::fcntl(i, F_GETFD); |
915 | |
916 | fd_map[i] = ((flags >= 0) && !(flags & FD_CLOEXEC)) |
917 | ? i : SPAWN_FDCLOSED; |
918 | } |
919 | |
920 | switch (processChannelMode) { |
921 | case QProcess::ForwardedChannels: |
922 | fd_map[0] = stdinChannel.pipe[0]; |
923 | fd_map[1] = QT_FILENO(stdout); |
924 | fd_map[2] = QT_FILENO(stderr); |
925 | break; |
926 | case QProcess::MergedChannels: |
927 | fd_map[0] = stdinChannel.pipe[0]; |
928 | fd_map[1] = stdoutChannel.pipe[1]; |
929 | fd_map[2] = stdoutChannel.pipe[1]; |
930 | break; |
931 | case QProcess::SeparateChannels: |
932 | fd_map[0] = stdinChannel.pipe[0]; |
933 | fd_map[1] = stdoutChannel.pipe[1]; |
934 | fd_map[2] = stderrChannel.pipe[1]; |
935 | break; |
936 | } |
937 | |
938 | pid_t childPid = doSpawn(fd_count, fd_map.data(), argv, envp, workingDir, false); |
939 | |
940 | if (childPid == -1) { |
941 | QString error = qt_error_string(errno); |
942 | qt_safe_write(childStartedPipe[1], error.data(), error.length() * sizeof(QChar)); |
943 | qt_safe_close(childStartedPipe[1]); |
944 | childStartedPipe[1] = -1; |
945 | } |
946 | |
947 | return childPid; |
948 | } |
949 | #endif // Q_OS_QNX |
950 | |
951 | qint64 QProcessPrivate::bytesAvailableFromStdout() const |
952 | { |
953 | int nbytes = 0; |
954 | qint64 available = 0; |
955 | if (::ioctl(stdoutChannel.pipe[0], FIONREAD, (char *) &nbytes) >= 0) |
956 | available = (qint64) nbytes; |
957 | #if defined (QPROCESS_DEBUG) |
958 | qDebug("QProcessPrivate::bytesAvailableFromStdout() == %lld" , available); |
959 | #endif |
960 | return available; |
961 | } |
962 | |
963 | qint64 QProcessPrivate::bytesAvailableFromStderr() const |
964 | { |
965 | int nbytes = 0; |
966 | qint64 available = 0; |
967 | if (::ioctl(stderrChannel.pipe[0], FIONREAD, (char *) &nbytes) >= 0) |
968 | available = (qint64) nbytes; |
969 | #if defined (QPROCESS_DEBUG) |
970 | qDebug("QProcessPrivate::bytesAvailableFromStderr() == %lld" , available); |
971 | #endif |
972 | return available; |
973 | } |
974 | |
975 | qint64 QProcessPrivate::readFromStdout(char *data, qint64 maxlen) |
976 | { |
977 | qint64 bytesRead = qt_safe_read(stdoutChannel.pipe[0], data, maxlen); |
978 | #if defined QPROCESS_DEBUG |
979 | qDebug("QProcessPrivate::readFromStdout(%p \"%s\", %lld) == %lld" , |
980 | data, qt_prettyDebug(data, bytesRead, 16).constData(), maxlen, bytesRead); |
981 | #endif |
982 | return bytesRead; |
983 | } |
984 | |
985 | qint64 QProcessPrivate::readFromStderr(char *data, qint64 maxlen) |
986 | { |
987 | qint64 bytesRead = qt_safe_read(stderrChannel.pipe[0], data, maxlen); |
988 | #if defined QPROCESS_DEBUG |
989 | qDebug("QProcessPrivate::readFromStderr(%p \"%s\", %lld) == %lld" , |
990 | data, qt_prettyDebug(data, bytesRead, 16).constData(), maxlen, bytesRead); |
991 | #endif |
992 | return bytesRead; |
993 | } |
994 | |
995 | qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen) |
996 | { |
997 | qint64 written = qt_safe_write_nosignal(stdinChannel.pipe[1], data, maxlen); |
998 | #if defined QPROCESS_DEBUG |
999 | qDebug("QProcessPrivate::writeToStdin(%p \"%s\", %lld) == %lld" , |
1000 | data, qt_prettyDebug(data, maxlen, 16).constData(), maxlen, written); |
1001 | if (written == -1) |
1002 | qDebug("QProcessPrivate::writeToStdin(), failed to write (%s)" , qPrintable(qt_error_string(errno))); |
1003 | #endif |
1004 | // If the O_NONBLOCK flag is set and If some data can be written without blocking |
1005 | // the process, write() will transfer what it can and return the number of bytes written. |
1006 | // Otherwise, it will return -1 and set errno to EAGAIN |
1007 | if (written == -1 && errno == EAGAIN) |
1008 | written = 0; |
1009 | return written; |
1010 | } |
1011 | |
1012 | void QProcessPrivate::terminateProcess() |
1013 | { |
1014 | #if defined (QPROCESS_DEBUG) |
1015 | qDebug("QProcessPrivate::killProcess()" ); |
1016 | #endif |
1017 | if (pid) |
1018 | ::kill(pid_t(pid), SIGTERM); |
1019 | } |
1020 | |
1021 | void QProcessPrivate::killProcess() |
1022 | { |
1023 | #if defined (QPROCESS_DEBUG) |
1024 | qDebug("QProcessPrivate::killProcess()" ); |
1025 | #endif |
1026 | if (pid) |
1027 | ::kill(pid_t(pid), SIGKILL); |
1028 | } |
1029 | |
1030 | static int select_msecs(int nfds, fd_set *fdread, fd_set *fdwrite, int timeout) |
1031 | { |
1032 | if (timeout < 0) |
1033 | return qt_safe_select(nfds, fdread, fdwrite, 0, 0); |
1034 | |
1035 | struct timeval tv; |
1036 | tv.tv_sec = timeout / 1000; |
1037 | tv.tv_usec = (timeout % 1000) * 1000; |
1038 | return qt_safe_select(nfds, fdread, fdwrite, 0, &tv); |
1039 | } |
1040 | |
1041 | /* |
1042 | Returns the difference between msecs and elapsed. If msecs is -1, |
1043 | however, -1 is returned. |
1044 | */ |
1045 | static int qt_timeout_value(int msecs, int elapsed) |
1046 | { |
1047 | if (msecs == -1) |
1048 | return -1; |
1049 | |
1050 | int timeout = msecs - elapsed; |
1051 | return timeout < 0 ? 0 : timeout; |
1052 | } |
1053 | |
1054 | bool QProcessPrivate::waitForStarted(int msecs) |
1055 | { |
1056 | Q_Q(QProcess); |
1057 | |
1058 | #if defined (QPROCESS_DEBUG) |
1059 | qDebug("QProcessPrivate::waitForStarted(%d) waiting for child to start (fd = %d)" , msecs, |
1060 | childStartedPipe[0]); |
1061 | #endif |
1062 | |
1063 | fd_set fds; |
1064 | FD_ZERO(&fds); |
1065 | FD_SET(childStartedPipe[0], &fds); |
1066 | if (select_msecs(childStartedPipe[0] + 1, &fds, 0, msecs) == 0) { |
1067 | processError = QProcess::Timedout; |
1068 | q->setErrorString(QProcess::tr("Process operation timed out" )); |
1069 | #if defined (QPROCESS_DEBUG) |
1070 | qDebug("QProcessPrivate::waitForStarted(%d) == false (timed out)" , msecs); |
1071 | #endif |
1072 | return false; |
1073 | } |
1074 | |
1075 | bool startedEmitted = _q_startupNotification(); |
1076 | #if defined (QPROCESS_DEBUG) |
1077 | qDebug("QProcessPrivate::waitForStarted() == %s" , startedEmitted ? "true" : "false" ); |
1078 | #endif |
1079 | return startedEmitted; |
1080 | } |
1081 | |
1082 | bool QProcessPrivate::waitForReadyRead(int msecs) |
1083 | { |
1084 | Q_Q(QProcess); |
1085 | #if defined (QPROCESS_DEBUG) |
1086 | qDebug("QProcessPrivate::waitForReadyRead(%d)" , msecs); |
1087 | #endif |
1088 | |
1089 | QElapsedTimer stopWatch; |
1090 | stopWatch.start(); |
1091 | |
1092 | forever { |
1093 | fd_set fdread; |
1094 | fd_set fdwrite; |
1095 | |
1096 | FD_ZERO(&fdread); |
1097 | FD_ZERO(&fdwrite); |
1098 | |
1099 | int nfds = deathPipe[0]; |
1100 | FD_SET(deathPipe[0], &fdread); |
1101 | |
1102 | if (processState == QProcess::Starting) |
1103 | add_fd(nfds, childStartedPipe[0], &fdread); |
1104 | |
1105 | if (stdoutChannel.pipe[0] != -1) |
1106 | add_fd(nfds, stdoutChannel.pipe[0], &fdread); |
1107 | if (stderrChannel.pipe[0] != -1) |
1108 | add_fd(nfds, stderrChannel.pipe[0], &fdread); |
1109 | |
1110 | if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1) |
1111 | add_fd(nfds, stdinChannel.pipe[1], &fdwrite); |
1112 | |
1113 | int timeout = qt_timeout_value(msecs, stopWatch.elapsed()); |
1114 | int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout); |
1115 | if (ret < 0) { |
1116 | break; |
1117 | } |
1118 | if (ret == 0) { |
1119 | processError = QProcess::Timedout; |
1120 | q->setErrorString(QProcess::tr("Process operation timed out" )); |
1121 | return false; |
1122 | } |
1123 | |
1124 | if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) { |
1125 | if (!_q_startupNotification()) |
1126 | return false; |
1127 | } |
1128 | |
1129 | bool readyReadEmitted = false; |
1130 | if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread)) { |
1131 | bool canRead = _q_canReadStandardOutput(); |
1132 | if (processChannel == QProcess::StandardOutput && canRead) |
1133 | readyReadEmitted = true; |
1134 | } |
1135 | if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread)) { |
1136 | bool canRead = _q_canReadStandardError(); |
1137 | if (processChannel == QProcess::StandardError && canRead) |
1138 | readyReadEmitted = true; |
1139 | } |
1140 | if (readyReadEmitted) |
1141 | return true; |
1142 | |
1143 | if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite)) |
1144 | _q_canWrite(); |
1145 | |
1146 | if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) { |
1147 | if (_q_processDied()) |
1148 | return false; |
1149 | } |
1150 | } |
1151 | return false; |
1152 | } |
1153 | |
1154 | bool QProcessPrivate::waitForBytesWritten(int msecs) |
1155 | { |
1156 | Q_Q(QProcess); |
1157 | #if defined (QPROCESS_DEBUG) |
1158 | qDebug("QProcessPrivate::waitForBytesWritten(%d)" , msecs); |
1159 | #endif |
1160 | |
1161 | QElapsedTimer stopWatch; |
1162 | stopWatch.start(); |
1163 | |
1164 | while (!writeBuffer.isEmpty()) { |
1165 | fd_set fdread; |
1166 | fd_set fdwrite; |
1167 | |
1168 | FD_ZERO(&fdread); |
1169 | FD_ZERO(&fdwrite); |
1170 | |
1171 | int nfds = deathPipe[0]; |
1172 | FD_SET(deathPipe[0], &fdread); |
1173 | |
1174 | if (processState == QProcess::Starting) |
1175 | add_fd(nfds, childStartedPipe[0], &fdread); |
1176 | |
1177 | if (stdoutChannel.pipe[0] != -1) |
1178 | add_fd(nfds, stdoutChannel.pipe[0], &fdread); |
1179 | if (stderrChannel.pipe[0] != -1) |
1180 | add_fd(nfds, stderrChannel.pipe[0], &fdread); |
1181 | |
1182 | |
1183 | if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1) |
1184 | add_fd(nfds, stdinChannel.pipe[1], &fdwrite); |
1185 | |
1186 | int timeout = qt_timeout_value(msecs, stopWatch.elapsed()); |
1187 | int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout); |
1188 | if (ret < 0) { |
1189 | break; |
1190 | } |
1191 | |
1192 | if (ret == 0) { |
1193 | processError = QProcess::Timedout; |
1194 | q->setErrorString(QProcess::tr("Process operation timed out" )); |
1195 | return false; |
1196 | } |
1197 | |
1198 | if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) { |
1199 | if (!_q_startupNotification()) |
1200 | return false; |
1201 | } |
1202 | |
1203 | if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite)) |
1204 | return _q_canWrite(); |
1205 | |
1206 | if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread)) |
1207 | _q_canReadStandardOutput(); |
1208 | |
1209 | if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread)) |
1210 | _q_canReadStandardError(); |
1211 | |
1212 | if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) { |
1213 | if (_q_processDied()) |
1214 | return false; |
1215 | } |
1216 | } |
1217 | |
1218 | return false; |
1219 | } |
1220 | |
1221 | bool QProcessPrivate::waitForFinished(int msecs) |
1222 | { |
1223 | Q_Q(QProcess); |
1224 | #if defined (QPROCESS_DEBUG) |
1225 | qDebug("QProcessPrivate::waitForFinished(%d)" , msecs); |
1226 | #endif |
1227 | |
1228 | QElapsedTimer stopWatch; |
1229 | stopWatch.start(); |
1230 | |
1231 | forever { |
1232 | fd_set fdread; |
1233 | fd_set fdwrite; |
1234 | int nfds = -1; |
1235 | |
1236 | FD_ZERO(&fdread); |
1237 | FD_ZERO(&fdwrite); |
1238 | |
1239 | if (processState == QProcess::Starting) |
1240 | add_fd(nfds, childStartedPipe[0], &fdread); |
1241 | |
1242 | if (stdoutChannel.pipe[0] != -1) |
1243 | add_fd(nfds, stdoutChannel.pipe[0], &fdread); |
1244 | if (stderrChannel.pipe[0] != -1) |
1245 | add_fd(nfds, stderrChannel.pipe[0], &fdread); |
1246 | |
1247 | if (processState == QProcess::Running) |
1248 | add_fd(nfds, deathPipe[0], &fdread); |
1249 | |
1250 | if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1) |
1251 | add_fd(nfds, stdinChannel.pipe[1], &fdwrite); |
1252 | |
1253 | int timeout = qt_timeout_value(msecs, stopWatch.elapsed()); |
1254 | int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout); |
1255 | if (ret < 0) { |
1256 | break; |
1257 | } |
1258 | if (ret == 0) { |
1259 | processError = QProcess::Timedout; |
1260 | q->setErrorString(QProcess::tr("Process operation timed out" )); |
1261 | return false; |
1262 | } |
1263 | |
1264 | if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) { |
1265 | if (!_q_startupNotification()) |
1266 | return false; |
1267 | } |
1268 | if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite)) |
1269 | _q_canWrite(); |
1270 | |
1271 | if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread)) |
1272 | _q_canReadStandardOutput(); |
1273 | |
1274 | if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread)) |
1275 | _q_canReadStandardError(); |
1276 | |
1277 | if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) { |
1278 | if (_q_processDied()) |
1279 | return true; |
1280 | } |
1281 | } |
1282 | return false; |
1283 | } |
1284 | |
1285 | bool QProcessPrivate::waitForWrite(int msecs) |
1286 | { |
1287 | fd_set fdwrite; |
1288 | FD_ZERO(&fdwrite); |
1289 | FD_SET(stdinChannel.pipe[1], &fdwrite); |
1290 | return select_msecs(stdinChannel.pipe[1] + 1, 0, &fdwrite, msecs < 0 ? 0 : msecs) == 1; |
1291 | } |
1292 | |
1293 | void QProcessPrivate::findExitCode() |
1294 | { |
1295 | Q_Q(QProcess); |
1296 | processManager()->remove(q); |
1297 | } |
1298 | |
1299 | bool QProcessPrivate::waitForDeadChild() |
1300 | { |
1301 | Q_Q(QProcess); |
1302 | |
1303 | // read a byte from the death pipe |
1304 | char c; |
1305 | qt_safe_read(deathPipe[0], &c, 1); |
1306 | |
1307 | // check if our process is dead |
1308 | int exitStatus; |
1309 | if (qt_safe_waitpid(pid_t(pid), &exitStatus, WNOHANG) > 0) { |
1310 | processManager()->remove(q); |
1311 | crashed = !WIFEXITED(exitStatus); |
1312 | exitCode = WEXITSTATUS(exitStatus); |
1313 | #if defined QPROCESS_DEBUG |
1314 | qDebug() << "QProcessPrivate::waitForDeadChild() dead with exitCode" |
1315 | << exitCode << ", crashed?" << crashed; |
1316 | #endif |
1317 | return true; |
1318 | } |
1319 | #if defined QPROCESS_DEBUG |
1320 | qDebug() << "QProcessPrivate::waitForDeadChild() not dead!" ; |
1321 | #endif |
1322 | return false; |
1323 | } |
1324 | |
1325 | void QProcessPrivate::_q_notified() |
1326 | { |
1327 | } |
1328 | |
1329 | #if defined(Q_OS_QNX) |
1330 | bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid) |
1331 | { |
1332 | const int fd_count = 3; |
1333 | int fd_map[fd_count] = { QT_FILENO(stdin), QT_FILENO(stdout), QT_FILENO(stderr) }; |
1334 | |
1335 | QList<QByteArray> enc_args; |
1336 | enc_args.append(QFile::encodeName(program)); |
1337 | for (int i = 0; i < arguments.size(); ++i) |
1338 | enc_args.append(arguments.at(i).toLocal8Bit()); |
1339 | |
1340 | const int argc = enc_args.size(); |
1341 | QScopedArrayPointer<char*> raw_argv(new char*[argc + 1]); |
1342 | for (int i = 0; i < argc; ++i) |
1343 | raw_argv[i] = const_cast<char *>(enc_args.at(i).data()); |
1344 | raw_argv[argc] = 0; |
1345 | |
1346 | char **envp = 0; // inherit environment |
1347 | |
1348 | // Encode the working directory if it's non-empty, otherwise just pass 0. |
1349 | const char *workingDirPtr = 0; |
1350 | QByteArray encodedWorkingDirectory; |
1351 | if (!workingDirectory.isEmpty()) { |
1352 | encodedWorkingDirectory = QFile::encodeName(workingDirectory); |
1353 | workingDirPtr = encodedWorkingDirectory.constData(); |
1354 | } |
1355 | |
1356 | pid_t childPid = doSpawn(fd_count, fd_map, raw_argv.data(), envp, workingDirPtr, true); |
1357 | if (pid && childPid != -1) |
1358 | *pid = childPid; |
1359 | |
1360 | return childPid != -1; |
1361 | } |
1362 | |
1363 | #else |
1364 | |
1365 | bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid) |
1366 | { |
1367 | processManager()->start(); |
1368 | |
1369 | QByteArray encodedWorkingDirectory = QFile::encodeName(workingDirectory); |
1370 | |
1371 | // To catch the startup of the child |
1372 | int startedPipe[2]; |
1373 | if (qt_safe_pipe(startedPipe) != 0) |
1374 | return false; |
1375 | // To communicate the pid of the child |
1376 | int pidPipe[2]; |
1377 | if (qt_safe_pipe(pidPipe) != 0) { |
1378 | qt_safe_close(startedPipe[0]); |
1379 | qt_safe_close(startedPipe[1]); |
1380 | return false; |
1381 | } |
1382 | |
1383 | pid_t childPid = fork(); |
1384 | if (childPid == 0) { |
1385 | struct sigaction noaction; |
1386 | memset(&noaction, 0, sizeof(noaction)); |
1387 | noaction.sa_handler = SIG_IGN; |
1388 | ::sigaction(SIGPIPE, &noaction, 0); |
1389 | |
1390 | ::setsid(); |
1391 | |
1392 | qt_safe_close(startedPipe[0]); |
1393 | qt_safe_close(pidPipe[0]); |
1394 | |
1395 | pid_t doubleForkPid = fork(); |
1396 | if (doubleForkPid == 0) { |
1397 | qt_safe_close(pidPipe[1]); |
1398 | |
1399 | if (!encodedWorkingDirectory.isEmpty()) |
1400 | QT_CHDIR(encodedWorkingDirectory.constData()); |
1401 | |
1402 | char **argv = new char *[arguments.size() + 2]; |
1403 | for (int i = 0; i < arguments.size(); ++i) { |
1404 | #ifdef Q_OS_MAC |
1405 | argv[i + 1] = ::strdup(arguments.at(i).toUtf8().constData()); |
1406 | #else |
1407 | argv[i + 1] = ::strdup(arguments.at(i).toLocal8Bit().constData()); |
1408 | #endif |
1409 | } |
1410 | argv[arguments.size() + 1] = 0; |
1411 | |
1412 | if (!program.contains(QLatin1Char('/'))) { |
1413 | const QString path = QString::fromLocal8Bit(::getenv("PATH" )); |
1414 | if (!path.isEmpty()) { |
1415 | QStringList pathEntries = path.split(QLatin1Char(':')); |
1416 | for (int k = 0; k < pathEntries.size(); ++k) { |
1417 | QByteArray tmp = QFile::encodeName(pathEntries.at(k)); |
1418 | if (!tmp.endsWith('/')) tmp += '/'; |
1419 | tmp += QFile::encodeName(program); |
1420 | argv[0] = tmp.data(); |
1421 | qt_safe_execv(argv[0], argv); |
1422 | } |
1423 | } |
1424 | } else { |
1425 | QByteArray tmp = QFile::encodeName(program); |
1426 | argv[0] = tmp.data(); |
1427 | qt_safe_execv(argv[0], argv); |
1428 | } |
1429 | |
1430 | struct sigaction noaction; |
1431 | memset(&noaction, 0, sizeof(noaction)); |
1432 | noaction.sa_handler = SIG_IGN; |
1433 | ::sigaction(SIGPIPE, &noaction, 0); |
1434 | |
1435 | // '\1' means execv failed |
1436 | char c = '\1'; |
1437 | qt_safe_write(startedPipe[1], &c, 1); |
1438 | qt_safe_close(startedPipe[1]); |
1439 | ::_exit(1); |
1440 | } else if (doubleForkPid == -1) { |
1441 | struct sigaction noaction; |
1442 | memset(&noaction, 0, sizeof(noaction)); |
1443 | noaction.sa_handler = SIG_IGN; |
1444 | ::sigaction(SIGPIPE, &noaction, 0); |
1445 | |
1446 | // '\2' means internal error |
1447 | char c = '\2'; |
1448 | qt_safe_write(startedPipe[1], &c, 1); |
1449 | } |
1450 | |
1451 | qt_safe_close(startedPipe[1]); |
1452 | qt_safe_write(pidPipe[1], (const char *)&doubleForkPid, sizeof(pid_t)); |
1453 | QT_CHDIR("/" ); |
1454 | ::_exit(1); |
1455 | } |
1456 | |
1457 | qt_safe_close(startedPipe[1]); |
1458 | qt_safe_close(pidPipe[1]); |
1459 | |
1460 | if (childPid == -1) { |
1461 | qt_safe_close(startedPipe[0]); |
1462 | qt_safe_close(pidPipe[0]); |
1463 | return false; |
1464 | } |
1465 | |
1466 | char reply = '\0'; |
1467 | int startResult = qt_safe_read(startedPipe[0], &reply, 1); |
1468 | int result; |
1469 | qt_safe_close(startedPipe[0]); |
1470 | qt_safe_waitpid(childPid, &result, 0); |
1471 | bool success = (startResult != -1 && reply == '\0'); |
1472 | if (success && pid) { |
1473 | pid_t actualPid = 0; |
1474 | if (qt_safe_read(pidPipe[0], (char *)&actualPid, sizeof(pid_t)) == sizeof(pid_t)) { |
1475 | *pid = actualPid; |
1476 | } else { |
1477 | *pid = 0; |
1478 | } |
1479 | } |
1480 | qt_safe_close(pidPipe[0]); |
1481 | return success; |
1482 | } |
1483 | #endif // Q_OS_QNX |
1484 | |
1485 | void QProcessPrivate::initializeProcessManager() |
1486 | { |
1487 | (void) processManager(); |
1488 | } |
1489 | |
1490 | QT_END_NAMESPACE |
1491 | |
1492 | #include "qprocess_unix.moc" |
1493 | |
1494 | #endif // QT_NO_PROCESS |
1495 | |