~ubuntu-branches/ubuntu/quantal/psi/quantal

« back to all changes in this revision

Viewing changes to cutestuff/openpgp/gpgproc/jprocess_unix.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2006-01-20 00:20:36 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060120002036-7nw6yo6totip0ee5
Tags: 0.10-2
* Added upstream changelog (Closes: Bug#327748)
* Mention --no-gpg and --no-gpg-agent in manpage (Closes: Bug#204416)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/****************************************************************************
2
 
** $Id: jprocess_unix.cpp,v 1.13 2004/06/07 07:30:04 justin Exp $
3
 
**
4
 
** Implementation of QProcess class for Unix
5
 
**
6
 
** Created : 20000905
7
 
**
8
 
** Copyright (C) 1992-2003 Trolltech AS.  All rights reserved.
9
 
**
10
 
** This file is part of the kernel module of the Qt GUI Toolkit.
11
 
**
12
 
** This file may be distributed under the terms of the Q Public License
13
 
** as defined by Trolltech AS of Norway and appearing in the file
14
 
** LICENSE.QPL included in the packaging of this file.
15
 
**
16
 
** This file may be distributed and/or modified under the terms of the
17
 
** GNU General Public License version 2 as published by the Free Software
18
 
** Foundation and appearing in the file LICENSE.GPL included in the
19
 
** packaging of this file.
20
 
**
21
 
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22
 
** licenses may use this file in accordance with the Qt Commercial License
23
 
** Agreement provided with the Software.
24
 
**
25
 
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26
 
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27
 
**
28
 
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29
 
**   information about Qt Commercial License Agreements.
30
 
** See http://www.trolltech.com/qpl/ for QPL licensing information.
31
 
** See http://www.trolltech.com/gpl/ for GPL licensing information.
32
 
**
33
 
** Contact info@trolltech.com if any conditions of this licensing are
34
 
** not clear to you.
35
 
**
36
 
**********************************************************************/
37
 
 
38
 
#include "qplatformdefs.h"
39
 
 
40
 
// Solaris redefines connect -> __xnet_connect with _XOPEN_SOURCE_EXTENDED.
41
 
#if defined(connect)
42
 
#undef connect
43
 
#endif
44
 
 
45
 
//#include "qprocess.h"
46
 
#include "jprocess.h"
47
 
 
48
 
#ifndef QT_NO_PROCESS
49
 
 
50
 
#include "qapplication.h"
51
 
#include "qptrqueue.h"
52
 
#include "qptrlist.h"
53
 
#include "qsocketnotifier.h"
54
 
#include "qtimer.h"
55
 
#include "qcleanuphandler.h"
56
 
#include "qregexp.h"
57
 
#include "qguardedptr.h"
58
 
 
59
 
// table to hold callbacks -- Justin
60
 
struct JP_CALLBACK
61
 
{
62
 
        void (*childStarting)(JProcess *);
63
 
        JProcess *p;
64
 
};
65
 
 
66
 
static QPtrList<JP_CALLBACK> jp_callback_list;
67
 
 
68
 
static JP_CALLBACK *findCallback(JProcess *p)
69
 
{
70
 
        QPtrListIterator<JP_CALLBACK> it(jp_callback_list);
71
 
        for(JP_CALLBACK *cb; (cb = it.current()); ++it) {
72
 
                if(cb->p == p)
73
 
                        return cb;
74
 
        }
75
 
        return 0;
76
 
}
77
 
 
78
 
static void setCallback(void (*childStarting)(JProcess *), JProcess *p)
79
 
{
80
 
        JP_CALLBACK *cb = findCallback(p);
81
 
        if(childStarting) {
82
 
                if(!cb) {
83
 
                        cb = new JP_CALLBACK;
84
 
                        cb->p = p;
85
 
                        jp_callback_list.append(cb);
86
 
                }
87
 
                cb->childStarting = childStarting;
88
 
        }
89
 
        else {
90
 
                if(cb) {
91
 
                        jp_callback_list.removeRef(cb);
92
 
                        delete cb;
93
 
                }
94
 
        }
95
 
}
96
 
 
97
 
static void callCallback(JProcess *p)
98
 
{
99
 
        JP_CALLBACK *cb = findCallback(p);
100
 
        if(cb)
101
 
                cb->childStarting(p);
102
 
}
103
 
 
104
 
 
105
 
#include <stdlib.h>
106
 
#include <errno.h>
107
 
 
108
 
#ifdef __MIPSEL__
109
 
# ifndef SOCK_DGRAM
110
 
#  define SOCK_DGRAM 1
111
 
# endif
112
 
# ifndef SOCK_STREAM
113
 
#  define SOCK_STREAM 2
114
 
# endif
115
 
#endif
116
 
 
117
 
//#define QT_QPROCESS_DEBUG
118
 
 
119
 
// Don't need this -- Justin
120
 
/*
121
 
#ifdef Q_C_CALLBACKS
122
 
extern "C" {
123
 
#endif // Q_C_CALLBACKS
124
 
 
125
 
    QT_SIGNAL_RETTYPE qt_C_sigchldHnd(QT_SIGNAL_ARGS);
126
 
 
127
 
#ifdef Q_C_CALLBACKS
128
 
}
129
 
#endif // Q_C_CALLBACKS
130
 
*/
131
 
 
132
 
class JProc;
133
 
class JProcessManager;
134
 
class JProcessPrivate
135
 
{
136
 
public:
137
 
    JProcessPrivate();
138
 
    ~JProcessPrivate();
139
 
 
140
 
    void closeOpenSocketsForChild();
141
 
    void newProc( pid_t pid, JProcess *process );
142
 
 
143
 
    QByteArray bufStdout;
144
 
    QByteArray bufStderr;
145
 
 
146
 
    QPtrQueue<QByteArray> stdinBuf;
147
 
 
148
 
    QSocketNotifier *notifierStdin;
149
 
    QSocketNotifier *notifierStdout;
150
 
    QSocketNotifier *notifierStderr;
151
 
 
152
 
    ssize_t stdinBufRead;
153
 
    JProc *proc;
154
 
 
155
 
    bool exitValuesCalculated;
156
 
    bool socketReadCalled;
157
 
 
158
 
    static JProcessManager *procManager;
159
 
};
160
 
 
161
 
/***********************************************************************
162
 
 *
163
 
 * QProc
164
 
 *
165
 
 **********************************************************************/
166
 
/*
167
 
  The class QProcess does not necessarily map exactly to the running
168
 
  child processes: if the process is finished, the QProcess class may still be
169
 
  there; furthermore a user can use QProcess to start more than one process.
170
 
 
171
 
  The helper-class QProc has the semantics that one instance of this class maps
172
 
  directly to a running child process.
173
 
*/
174
 
class JProc
175
 
{
176
 
public:
177
 
    JProc( pid_t p, JProcess *proc=0 ) : pid(p), process(proc)
178
 
    {
179
 
#if defined(QT_QPROCESS_DEBUG)
180
 
        qDebug( "QProc: Constructor for pid %d and QProcess %p", pid, process );
181
 
#endif
182
 
        socketStdin = 0;
183
 
        socketStdout = 0;
184
 
        socketStderr = 0;
185
 
    }
186
 
    ~JProc()
187
 
    {
188
 
#if defined(QT_QPROCESS_DEBUG)
189
 
        qDebug( "QProc: Destructor for pid %d and QProcess %p", pid, process );
190
 
#endif
191
 
        if ( process != 0 ) {
192
 
            if ( process->d->notifierStdin )
193
 
                process->d->notifierStdin->setEnabled( FALSE );
194
 
            if ( process->d->notifierStdout )
195
 
                process->d->notifierStdout->setEnabled( FALSE );
196
 
            if ( process->d->notifierStderr )
197
 
                process->d->notifierStderr->setEnabled( FALSE );
198
 
            process->d->proc = 0;
199
 
        }
200
 
        if( socketStdin != 0 )
201
 
            ::close( socketStdin );
202
 
        // ### close these sockets even on parent exit or is it better only on
203
 
        // sigchld (but what do I have to do with them on exit then)?
204
 
        if( socketStdout != 0 )
205
 
            ::close( socketStdout );
206
 
        if( socketStderr != 0 )
207
 
            ::close( socketStderr );
208
 
    }
209
 
 
210
 
    pid_t pid;
211
 
    int socketStdin;
212
 
    int socketStdout;
213
 
    int socketStderr;
214
 
    JProcess *process;
215
 
};
216
 
 
217
 
/***********************************************************************
218
 
 *
219
 
 * QProcessManager
220
 
 *
221
 
 **********************************************************************/
222
 
class JProcessManager : public QObject
223
 
{
224
 
    Q_OBJECT
225
 
 
226
 
public:
227
 
    JProcessManager();
228
 
    ~JProcessManager();
229
 
 
230
 
    void append( JProc *p );
231
 
    void remove( JProc *p );
232
 
 
233
 
    void cleanup();
234
 
 
235
 
public slots:
236
 
    void removeMe();
237
 
    void sigchldHnd( int );
238
 
 
239
 
public:
240
 
    struct sigaction oldactChld;
241
 
    struct sigaction oldactPipe;
242
 
    QPtrList<JProc> *procList;
243
 
    int sigchldFd[2];
244
 
 
245
 
private slots:
246
 
    void cleanupProcesses();
247
 
 
248
 
private:
249
 
    QSocketNotifier *sn;
250
 
    QTimer *pollTimer;
251
 
};
252
 
 
253
 
static QCleanupHandler<JProcessManager> qprocess_cleanup_procmanager;
254
 
 
255
 
#ifdef Q_OS_QNX6
256
 
#define BAILOUT close(tmpSocket);close(socketFD[1]);return -1;
257
 
int qnx6SocketPairReplacement (int socketFD[2]) {
258
 
    int tmpSocket;
259
 
    tmpSocket = socket (AF_INET, SOCK_STREAM, 0);
260
 
    if (tmpSocket == -1)
261
 
        return -1;
262
 
    socketFD[1] = socket(AF_INET, SOCK_STREAM, 0);
263
 
    if (socketFD[1] == -1) { BAILOUT };
264
 
 
265
 
    sockaddr_in ipAddr;
266
 
    memset(&ipAddr, 0, sizeof(ipAddr));
267
 
    ipAddr.sin_family = AF_INET;
268
 
    ipAddr.sin_addr.s_addr = INADDR_ANY;
269
 
 
270
 
    int socketOptions = 1;
271
 
    setsockopt(tmpSocket, SOL_SOCKET, SO_REUSEADDR, &socketOptions, sizeof(int));
272
 
 
273
 
    bool found = FALSE;
274
 
    for (int socketIP = 2000; (socketIP < 2500) && !(found); socketIP++) {
275
 
        ipAddr.sin_port = htons(socketIP);
276
 
        if (bind(tmpSocket, (struct sockaddr *)&ipAddr, sizeof(ipAddr)))
277
 
            found = TRUE;
278
 
    }
279
 
 
280
 
    if (listen(tmpSocket, 5)) { BAILOUT };
281
 
 
282
 
    // Select non-blocking mode
283
 
    int originalFlags = fcntl(socketFD[1], F_GETFL, 0);
284
 
    fcntl(socketFD[1], F_SETFL, originalFlags | O_NONBLOCK);
285
 
 
286
 
    // Request connection
287
 
    if (connect(socketFD[1], (struct sockaddr*)&ipAddr, sizeof(ipAddr)))
288
 
        if (errno != EINPROGRESS) { BAILOUT };
289
 
 
290
 
    // Accept connection
291
 
    socketFD[0] = accept(tmpSocket, (struct sockaddr *)NULL, (size_t *)NULL);
292
 
    if(socketFD[0] == -1) { BAILOUT };
293
 
 
294
 
    // We're done
295
 
    close(tmpSocket);
296
 
 
297
 
    // Restore original flags , ie return to blocking
298
 
    fcntl(socketFD[1], F_SETFL, originalFlags);
299
 
    return 0;
300
 
}
301
 
#undef BAILOUT
302
 
#endif
303
 
 
304
 
JProcessManager::JProcessManager() : sn(0)
305
 
{
306
 
    procList = new QPtrList<JProc>;
307
 
    procList->setAutoDelete( TRUE );
308
 
 
309
 
    // really lame workaround -- Justin
310
 
    pollTimer = new QTimer(this);
311
 
    connect(pollTimer, SIGNAL(timeout()), SLOT(cleanupProcesses()));
312
 
 
313
 
    // The SIGCHLD handler writes to a socket to tell the manager that
314
 
    // something happened. This is done to get the processing in sync with the
315
 
    // event reporting.
316
 
#ifndef Q_OS_QNX6
317
 
    if ( ::socketpair( AF_UNIX, SOCK_STREAM, 0, sigchldFd ) ) {
318
 
#else
319
 
    if ( qnx6SocketPairReplacement (sigchldFd) ) {
320
 
#endif
321
 
        sigchldFd[0] = 0;
322
 
        sigchldFd[1] = 0;
323
 
    } else {
324
 
#if defined(QT_QPROCESS_DEBUG)
325
 
        qDebug( "QProcessManager: install socket notifier (%d)", sigchldFd[1] );
326
 
#endif
327
 
        sn = new QSocketNotifier( sigchldFd[1],
328
 
                QSocketNotifier::Read, this );
329
 
        connect( sn, SIGNAL(activated(int)),
330
 
                this, SLOT(sigchldHnd(int)) );
331
 
        sn->setEnabled( TRUE );
332
 
    }
333
 
 
334
 
    // install a SIGCHLD handler and ignore SIGPIPE
335
 
    struct sigaction act;
336
 
 
337
 
    // NO SIGCHLD -- Justin
338
 
/*
339
 
#if defined(QT_QPROCESS_DEBUG)
340
 
    qDebug( "QProcessManager: install a SIGCHLD handler" );
341
 
#endif
342
 
    act.sa_handler = qt_C_sigchldHnd;
343
 
    sigemptyset( &(act.sa_mask) );
344
 
    sigaddset( &(act.sa_mask), SIGCHLD );
345
 
    act.sa_flags = SA_NOCLDSTOP;
346
 
#if defined(SA_RESTART)
347
 
    act.sa_flags |= SA_RESTART;
348
 
#endif
349
 
    if ( sigaction( SIGCHLD, &act, &oldactChld ) != 0 )
350
 
        qWarning( "Error installing SIGCHLD handler" );
351
 
*/
352
 
 
353
 
    // obtain current handler
354
 
    if ( sigaction( SIGPIPE, NULL, &act ) == 0 ) {
355
 
     // already ignoring?
356
 
     if(act.sa_handler == QT_SIGNAL_IGNORE) {
357
 
       // do nothing
358
 
     }
359
 
     else {
360
 
#if defined(QT_QPROCESS_DEBUG)
361
 
      qDebug( "QProcessManager: install a SIGPIPE handler (SIG_IGN)" );
362
 
#endif
363
 
      act.sa_handler = QT_SIGNAL_IGNORE;
364
 
      sigemptyset( &(act.sa_mask) );
365
 
      sigaddset( &(act.sa_mask), SIGPIPE );
366
 
      act.sa_flags = 0;
367
 
      if ( sigaction( SIGPIPE, &act, &oldactPipe ) != 0 )
368
 
          qWarning( "Error installing SIGPIPE handler" );
369
 
     }
370
 
    }
371
 
 
372
 
    pollTimer->start(100);
373
 
}
374
 
 
375
 
JProcessManager::~JProcessManager()
376
 
{
377
 
    delete procList;
378
 
 
379
 
    if ( sigchldFd[0] != 0 )
380
 
        ::close( sigchldFd[0] );
381
 
    if ( sigchldFd[1] != 0 )
382
 
        ::close( sigchldFd[1] );
383
 
 
384
 
// NO SIGCHLD -- Justin
385
 
/*
386
 
    // restore SIGCHLD handler
387
 
#if defined(QT_QPROCESS_DEBUG)
388
 
    qDebug( "QProcessManager: restore old sigchild handler" );
389
 
#endif
390
 
    if ( sigaction( SIGCHLD, &oldactChld, 0 ) != 0 )
391
 
        qWarning( "Error restoring SIGCHLD handler" );
392
 
*/
393
 
 
394
 
// NO SIGPIPE restore (we might trash the one from QProcess)
395
 
/*
396
 
#if defined(QT_QPROCESS_DEBUG)
397
 
    qDebug( "QProcessManager: restore old sigpipe handler" );
398
 
#endif
399
 
    if ( sigaction( SIGPIPE, &oldactPipe, 0 ) != 0 )
400
 
        qWarning( "Error restoring SIGPIPE handler" );
401
 
*/
402
 
}
403
 
 
404
 
void JProcessManager::append( JProc *p )
405
 
{
406
 
    procList->append( p );
407
 
#if defined(QT_QPROCESS_DEBUG)
408
 
    qDebug( "QProcessManager: append process (procList.count(): %d)", procList->count() );
409
 
#endif
410
 
}
411
 
 
412
 
void JProcessManager::remove( JProc *p )
413
 
{
414
 
    procList->remove( p );
415
 
#if defined(QT_QPROCESS_DEBUG)
416
 
    qDebug( "QProcessManager: remove process (procList.count(): %d)", procList->count() );
417
 
#endif
418
 
    cleanup();
419
 
}
420
 
 
421
 
void JProcessManager::cleanup()
422
 
{
423
 
    if ( procList->count() == 0 ) {
424
 
        QTimer::singleShot( 0, this, SLOT(removeMe()) );
425
 
    }
426
 
}
427
 
 
428
 
void JProcessManager::removeMe()
429
 
{
430
 
    if ( procList->count() == 0 ) {
431
 
        qprocess_cleanup_procmanager.remove( &JProcessPrivate::procManager );
432
 
        JProcessPrivate::procManager = 0;
433
 
        delete this;
434
 
    }
435
 
}
436
 
 
437
 
void JProcessManager::sigchldHnd( int fd )
438
 
{
439
 
    // Disable the socket notifier to make sure that this function is not
440
 
    // called recursively -- this can happen, if you enter the event loop in
441
 
    // the slot connected to the processExited() signal (e.g. by showing a
442
 
    // modal dialog) and there are more than one process which exited in the
443
 
    // meantime.
444
 
    if ( sn )
445
 
        sn->setEnabled( FALSE );
446
 
 
447
 
    char tmp;
448
 
    ::read( fd, &tmp, sizeof(tmp) );
449
 
#if defined(QT_QPROCESS_DEBUG)
450
 
    qDebug( "QProcessManager::sigchldHnd()" );
451
 
#endif
452
 
    JProc *proc;
453
 
    JProcess *process;
454
 
    bool removeProc;
455
 
    proc = procList->first();
456
 
    while ( proc != 0 ) {
457
 
        removeProc = FALSE;
458
 
        process = proc->process;
459
 
        if ( process != 0 ) {
460
 
            if ( !process->isRunning() ) {
461
 
#if defined(QT_QPROCESS_DEBUG)
462
 
                qDebug( "QProcessManager::sigchldHnd() (PID: %d): process exited (QProcess available)", proc->pid );
463
 
#endif
464
 
                /*
465
 
                  Apparently, there is not consistency among different
466
 
                  operating systems on how to use FIONREAD.
467
 
 
468
 
                  FreeBSD, Linux and Solaris all expect the 3rd
469
 
                  argument to ioctl() to be an int, which is normally
470
 
                  32-bit even on 64-bit machines.
471
 
 
472
 
                  IRIX, on the other hand, expects a size_t, which is
473
 
                  64-bit on 64-bit machines.
474
 
 
475
 
                  So, the solution is to use size_t initialized to
476
 
                  zero to make sure all bits are set to zero,
477
 
                  preventing underflow with the FreeBSD/Linux/Solaris
478
 
                  ioctls.
479
 
                */
480
 
                size_t nbytes = 0;
481
 
                // read pending data
482
 
                if ( ::ioctl(proc->socketStdout, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) {
483
 
#if defined(QT_QPROCESS_DEBUG)
484
 
                    qDebug( "QProcessManager::sigchldHnd() (PID: %d): reading %d bytes of pending data on stdout", proc->pid, nbytes );
485
 
#endif
486
 
                    process->socketRead( proc->socketStdout );
487
 
                }
488
 
                nbytes = 0;
489
 
                if ( ::ioctl(proc->socketStderr, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) {
490
 
#if defined(QT_QPROCESS_DEBUG)
491
 
                    qDebug( "QProcessManager::sigchldHnd() (PID: %d): reading %d bytes of pending data on stderr", proc->pid, nbytes );
492
 
#endif
493
 
                    process->socketRead( proc->socketStderr );
494
 
                }
495
 
 
496
 
                if ( process->notifyOnExit )
497
 
                    emit process->processExited();
498
 
 
499
 
                removeProc = TRUE;
500
 
            }
501
 
        } else {
502
 
            int status;
503
 
            if ( ::waitpid( proc->pid, &status, WNOHANG ) == proc->pid ) {
504
 
#if defined(QT_QPROCESS_DEBUG)
505
 
                qDebug( "QProcessManager::sigchldHnd() (PID: %d): process exited (QProcess not available)", proc->pid );
506
 
#endif
507
 
                removeProc = TRUE;
508
 
            }
509
 
        }
510
 
        if ( removeProc ) {
511
 
            JProc *oldproc = proc;
512
 
            proc = procList->next();
513
 
            remove( oldproc );
514
 
        } else {
515
 
            proc = procList->next();
516
 
        }
517
 
    }
518
 
    if ( sn )
519
 
        sn->setEnabled( TRUE );
520
 
}
521
 
 
522
 
void JProcessManager::cleanupProcesses()
523
 
{
524
 
    if ( JProcessPrivate::procManager == 0 )
525
 
        return;
526
 
    if ( JProcessPrivate::procManager->sigchldFd[0] == 0 )
527
 
        return;
528
 
 
529
 
    char a = 1;
530
 
    ::write( JProcessPrivate::procManager->sigchldFd[0], &a, sizeof(a) );
531
 
}
532
 
 
533
 
#include "jprocess_unix.moc"
534
 
 
535
 
 
536
 
/***********************************************************************
537
 
 *
538
 
 * QProcessPrivate
539
 
 *
540
 
 **********************************************************************/
541
 
JProcessManager *JProcessPrivate::procManager = 0;
542
 
 
543
 
JProcessPrivate::JProcessPrivate()
544
 
{
545
 
#if defined(QT_QPROCESS_DEBUG)
546
 
    qDebug( "QProcessPrivate: Constructor" );
547
 
#endif
548
 
    stdinBufRead = 0;
549
 
 
550
 
    notifierStdin = 0;
551
 
    notifierStdout = 0;
552
 
    notifierStderr = 0;
553
 
 
554
 
    exitValuesCalculated = FALSE;
555
 
    socketReadCalled = FALSE;
556
 
 
557
 
    proc = 0;
558
 
}
559
 
 
560
 
JProcessPrivate::~JProcessPrivate()
561
 
{
562
 
#if defined(QT_QPROCESS_DEBUG)
563
 
    qDebug( "QProcessPrivate: Destructor" );
564
 
#endif
565
 
 
566
 
    if ( proc != 0 ) {
567
 
        if ( proc->socketStdin != 0 ) {
568
 
            ::close( proc->socketStdin );
569
 
            proc->socketStdin = 0;
570
 
        }
571
 
        proc->process = 0;
572
 
    }
573
 
 
574
 
    while ( !stdinBuf.isEmpty() ) {
575
 
        delete stdinBuf.dequeue();
576
 
    }
577
 
    delete notifierStdin;
578
 
    delete notifierStdout;
579
 
    delete notifierStderr;
580
 
}
581
 
 
582
 
/*
583
 
  Closes all open sockets in the child process that are not needed by the child
584
 
  process. Otherwise one child may have an open socket on standard input, etc.
585
 
  of another child.
586
 
*/
587
 
void JProcessPrivate::closeOpenSocketsForChild()
588
 
{
589
 
    if ( procManager != 0 ) {
590
 
        if ( procManager->sigchldFd[0] != 0 )
591
 
            ::close( procManager->sigchldFd[0] );
592
 
        if ( procManager->sigchldFd[1] != 0 )
593
 
            ::close( procManager->sigchldFd[1] );
594
 
 
595
 
        // close also the sockets from other QProcess instances
596
 
        for ( JProc *p=procManager->procList->first(); p!=0; p=procManager->procList->next() ) {
597
 
            ::close( p->socketStdin );
598
 
            ::close( p->socketStdout );
599
 
            ::close( p->socketStderr );
600
 
        }
601
 
    }
602
 
}
603
 
 
604
 
void JProcessPrivate::newProc( pid_t pid, JProcess *process )
605
 
{
606
 
    proc = new JProc( pid, process );
607
 
    if ( procManager == 0 ) {
608
 
        procManager = new JProcessManager;
609
 
        qprocess_cleanup_procmanager.add( &procManager );
610
 
    }
611
 
    // the QProcessManager takes care of deleting the QProc instances
612
 
    procManager->append( proc );
613
 
}
614
 
 
615
 
/***********************************************************************
616
 
 *
617
 
 * sigchld handler callback
618
 
 *
619
 
 **********************************************************************/
620
 
// Don't need this -- Justin
621
 
/*QT_SIGNAL_RETTYPE qt_C_sigchldHnd( QT_SIGNAL_ARGS )
622
 
{
623
 
    if ( JProcessPrivate::procManager == 0 )
624
 
        return;
625
 
    if ( JProcessPrivate::procManager->sigchldFd[0] == 0 )
626
 
        return;
627
 
 
628
 
    char a = 1;
629
 
    ::write( JProcessPrivate::procManager->sigchldFd[0], &a, sizeof(a) );
630
 
}*/
631
 
 
632
 
/***********************************************************************
633
 
 *
634
 
 * QProcess
635
 
 *
636
 
 **********************************************************************/
637
 
/*
638
 
  This private class does basic initialization.
639
 
*/
640
 
void JProcess::init()
641
 
{
642
 
    d = new JProcessPrivate();
643
 
    exitStat = 0;
644
 
    exitNormal = FALSE;
645
 
}
646
 
 
647
 
/*
648
 
  This private class resets the process variables, etc. so that it can be used
649
 
  for another process to start.
650
 
*/
651
 
void JProcess::reset()
652
 
{
653
 
    delete d;
654
 
    d = new JProcessPrivate();
655
 
    exitStat = 0;
656
 
    exitNormal = FALSE;
657
 
    d->bufStdout.resize( 0 );
658
 
    d->bufStderr.resize( 0 );
659
 
}
660
 
 
661
 
QByteArray* JProcess::bufStdout()
662
 
{
663
 
    if ( d->proc && d->proc->socketStdout ) {
664
 
        /*
665
 
          Apparently, there is not consistency among different
666
 
          operating systems on how to use FIONREAD.
667
 
 
668
 
          FreeBSD, Linux and Solaris all expect the 3rd argument to
669
 
          ioctl() to be an int, which is normally 32-bit even on
670
 
          64-bit machines.
671
 
 
672
 
          IRIX, on the other hand, expects a size_t, which is 64-bit
673
 
          on 64-bit machines.
674
 
 
675
 
          So, the solution is to use size_t initialized to zero to
676
 
          make sure all bits are set to zero, preventing underflow
677
 
          with the FreeBSD/Linux/Solaris ioctls.
678
 
        */
679
 
        size_t nbytes = 0;
680
 
        if ( ::ioctl(d->proc->socketStdout, FIONREAD, (char*)&nbytes)==0 && nbytes>0 )
681
 
            socketRead( d->proc->socketStdout );
682
 
    }
683
 
    return &d->bufStdout;
684
 
}
685
 
 
686
 
QByteArray* JProcess::bufStderr()
687
 
{
688
 
    if ( d->proc && d->proc->socketStderr ) {
689
 
        /*
690
 
          Apparently, there is not consistency among different
691
 
          operating systems on how to use FIONREAD.
692
 
 
693
 
          FreeBSD, Linux and Solaris all expect the 3rd argument to
694
 
          ioctl() to be an int, which is normally 32-bit even on
695
 
          64-bit machines.
696
 
 
697
 
          IRIX, on the other hand, expects a size_t, which is 64-bit
698
 
          on 64-bit machines.
699
 
 
700
 
          So, the solution is to use size_t initialized to zero to
701
 
          make sure all bits are set to zero, preventing underflow
702
 
          with the FreeBSD/Linux/Solaris ioctls.
703
 
        */
704
 
        size_t nbytes = 0;
705
 
        if ( ::ioctl(d->proc->socketStderr, FIONREAD, (char*)&nbytes)==0 && nbytes>0 )
706
 
            socketRead( d->proc->socketStderr );
707
 
    }
708
 
    return &d->bufStderr;
709
 
}
710
 
 
711
 
void JProcess::consumeBufStdout( int consume )
712
 
{
713
 
    uint n = d->bufStdout.size();
714
 
    if ( consume==-1 || (uint)consume >= n ) {
715
 
        d->bufStdout.resize( 0 );
716
 
    } else {
717
 
        QByteArray tmp( n - consume );
718
 
        memcpy( tmp.data(), d->bufStdout.data()+consume, n-consume );
719
 
        d->bufStdout = tmp;
720
 
    }
721
 
}
722
 
 
723
 
void JProcess::consumeBufStderr( int consume )
724
 
{
725
 
    uint n = d->bufStderr.size();
726
 
    if ( consume==-1 || (uint)consume >= n ) {
727
 
        d->bufStderr.resize( 0 );
728
 
    } else {
729
 
        QByteArray tmp( n - consume );
730
 
        memcpy( tmp.data(), d->bufStderr.data()+consume, n-consume );
731
 
        d->bufStderr = tmp;
732
 
    }
733
 
}
734
 
 
735
 
/*!
736
 
    Destroys the instance.
737
 
 
738
 
    If the process is running, it is <b>not</b> terminated! The
739
 
    standard input, standard output and standard error of the process
740
 
    are closed.
741
 
 
742
 
    You can connect the destroyed() signal to the kill() slot, if you
743
 
    want the process to be terminated automatically when the instance
744
 
    is destroyed.
745
 
 
746
 
    \sa tryTerminate() kill()
747
 
*/
748
 
JProcess::~JProcess()
749
 
{
750
 
    setCallback(0, this);
751
 
    delete d;
752
 
}
753
 
 
754
 
/*!
755
 
    Tries to run a process for the command and arguments that were
756
 
    specified with setArguments(), addArgument() or that were
757
 
    specified in the constructor. The command is searched for in the
758
 
    path for executable programs; you can also use an absolute path in
759
 
    the command itself.
760
 
 
761
 
    If \a env is null, then the process is started with the same
762
 
    environment as the starting process. If \a env is non-null, then
763
 
    the values in the stringlist are interpreted as environment
764
 
    setttings of the form \c {key=value} and the process is started in
765
 
    these environment settings. For convenience, there is a small
766
 
    exception to this rule: under Unix, if \a env does not contain any
767
 
    settings for the environment variable \c LD_LIBRARY_PATH, then
768
 
    this variable is inherited from the starting process; under
769
 
    Windows the same applies for the environment variable \c PATH.
770
 
 
771
 
    Returns TRUE if the process could be started; otherwise returns
772
 
    FALSE.
773
 
 
774
 
    You can write data to the process's standard input with
775
 
    writeToStdin(). You can close standard input with closeStdin() and
776
 
    you can terminate the process with tryTerminate(), or with kill().
777
 
 
778
 
    You can call this function even if you've used this instance to
779
 
    create a another process which is still running. In such cases,
780
 
    QProcess closes the old process's standard input and deletes
781
 
    pending data, i.e., you lose all control over the old process, but
782
 
    the old process is not terminated. This applies also if the
783
 
    process could not be started. (On operating systems that have
784
 
    zombie processes, Qt will also wait() on the old process.)
785
 
 
786
 
    \sa launch() closeStdin()
787
 
*/
788
 
bool JProcess::start( QStringList *env )
789
 
{
790
 
#if defined(QT_QPROCESS_DEBUG)
791
 
    qDebug( "QProcess::start()" );
792
 
#endif
793
 
    reset();
794
 
 
795
 
    int sStdin[2];
796
 
    int sStdout[2];
797
 
    int sStderr[2];
798
 
 
799
 
    // open sockets for piping
800
 
#ifndef Q_OS_QNX6
801
 
    if ( (comms & Stdin) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdin ) == -1 ) {
802
 
#else
803
 
    if ( (comms & Stdin) && qnx6SocketPairReplacement(sStdin) == -1 ) {
804
 
#endif
805
 
        return FALSE;
806
 
    }
807
 
#ifndef Q_OS_QNX6
808
 
    if ( (comms & Stderr) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStderr ) == -1 ) {
809
 
#else
810
 
    if ( (comms & Stderr) && qnx6SocketPairReplacement(sStderr) == -1 ) {
811
 
#endif
812
 
        return FALSE;
813
 
    }
814
 
#ifndef Q_OS_QNX6
815
 
    if ( (comms & Stdout) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdout ) == -1 ) {
816
 
#else
817
 
    if ( (comms & Stdout) && qnx6SocketPairReplacement(sStdout) == -1 ) {
818
 
#endif
819
 
        return FALSE;
820
 
    }
821
 
 
822
 
    // the following pipe is only used to determine if the process could be
823
 
    // started
824
 
    int fd[2];
825
 
    if ( pipe( fd ) < 0 ) {
826
 
        // non critical error, go on
827
 
        fd[0] = 0;
828
 
        fd[1] = 0;
829
 
    }
830
 
 
831
 
    // construct the arguments for exec
832
 
    QCString *arglistQ = new QCString[ _arguments.count() + 1 ];
833
 
    const char** arglist = new const char*[ _arguments.count() + 1 ];
834
 
    int i = 0;
835
 
    for ( QStringList::Iterator it = _arguments.begin(); it != _arguments.end(); ++it ) {
836
 
        arglistQ[i] = (*it).local8Bit();
837
 
        arglist[i] = arglistQ[i];
838
 
#if defined(QT_QPROCESS_DEBUG)
839
 
        qDebug( "QProcess::start(): arg %d = %s", i, arglist[i] );
840
 
#endif
841
 
        i++;
842
 
    }
843
 
    arglist[i] = 0;
844
 
 
845
 
    // Must make sure signal handlers are installed before exec'ing
846
 
    // in case the process exits quickly.
847
 
    if ( d->procManager == 0 ) {
848
 
        d->procManager = new JProcessManager;
849
 
        qprocess_cleanup_procmanager.add( &d->procManager );
850
 
    }
851
 
 
852
 
    // fork and exec
853
 
    QApplication::flushX();
854
 
    pid_t pid = fork();
855
 
    if ( pid == 0 ) {
856
 
        callCallback(this);
857
 
        // child
858
 
        d->closeOpenSocketsForChild();
859
 
        if ( comms & Stdin ) {
860
 
            ::close( sStdin[1] );
861
 
            ::dup2( sStdin[0], STDIN_FILENO );
862
 
        }
863
 
        if ( comms & Stdout ) {
864
 
            ::close( sStdout[0] );
865
 
            ::dup2( sStdout[1], STDOUT_FILENO );
866
 
        }
867
 
        if ( comms & Stderr ) {
868
 
            ::close( sStderr[0] );
869
 
            ::dup2( sStderr[1], STDERR_FILENO );
870
 
        }
871
 
        if ( comms & DupStderr ) {
872
 
            ::dup2( STDOUT_FILENO, STDERR_FILENO );
873
 
        }
874
 
#ifndef QT_NO_DIR
875
 
        ::chdir( workingDir.absPath().latin1() );
876
 
#endif
877
 
        if ( fd[0] )
878
 
            ::close( fd[0] );
879
 
        if ( fd[1] )
880
 
            ::fcntl( fd[1], F_SETFD, FD_CLOEXEC ); // close on exec shows sucess
881
 
 
882
 
        if ( env == 0 ) { // inherit environment and start process
883
 
            QString command = _arguments[0];
884
 
#if defined(Q_OS_MACX) //look in a bundle
885
 
            const QString mac_bundle_suffix = ".app/Contents/MacOS/";
886
 
            if(!QFile::exists(command) && QFile::exists(command + mac_bundle_suffix)) {
887
 
                QString exec = command;
888
 
                int lslash = command.findRev('/');
889
 
                if(lslash != -1)
890
 
                    exec = command.mid(lslash+1);
891
 
                QFileInfo fileInfo( command + mac_bundle_suffix + exec );
892
 
                if ( fileInfo.isExecutable() )
893
 
                    command = fileInfo.absFilePath().local8Bit();
894
 
            }
895
 
#endif
896
 
#ifndef Q_OS_QNX4
897
 
            ::execvp( command, (char*const*)arglist ); // ### cast not nice
898
 
#else
899
 
            ::execvp( command, (char const*const*)arglist ); // ### cast not nice
900
 
#endif
901
 
        } else { // start process with environment settins as specified in env
902
 
            // construct the environment for exec
903
 
            int numEntries = env->count();
904
 
#if defined(Q_OS_MACX)
905
 
            QString ld_library_path("DYLD_LIBRARY_PATH");
906
 
#else
907
 
            QString ld_library_path("LD_LIBRARY_PATH");
908
 
#endif
909
 
            bool setLibraryPath =
910
 
                env->grep( QRegExp( "^" + ld_library_path + "=" ) ).empty() &&
911
 
                getenv( ld_library_path ) != 0;
912
 
            if ( setLibraryPath )
913
 
                numEntries++;
914
 
            QCString *envlistQ = new QCString[ numEntries + 1 ];
915
 
            const char** envlist = new const char*[ numEntries + 1 ];
916
 
            int i = 0;
917
 
            if ( setLibraryPath ) {
918
 
                envlistQ[i] = QString( ld_library_path + "=%1" ).arg( getenv( ld_library_path ) ).local8Bit();
919
 
                envlist[i] = envlistQ[i];
920
 
                i++;
921
 
            }
922
 
            for ( QStringList::Iterator it = env->begin(); it != env->end(); ++it ) {
923
 
                envlistQ[i] = (*it).local8Bit();
924
 
                envlist[i] = envlistQ[i];
925
 
                i++;
926
 
            }
927
 
            envlist[i] = 0;
928
 
 
929
 
            // look for the executable in the search path
930
 
            if ( _arguments.count()>0 && getenv("PATH")!=0 ) {
931
 
                QString command = _arguments[0];
932
 
                if ( !command.contains( '/' ) ) {
933
 
                    QStringList pathList = QStringList::split( ':', getenv( "PATH" ) );
934
 
                    for (QStringList::Iterator it = pathList.begin(); it != pathList.end(); ++it ) {
935
 
                        QString dir = *it;
936
 
#if defined(Q_OS_MACX) //look in a bundle
937
 
                        if(!QFile::exists(dir + "/" + command) && QFile::exists(dir + "/" + command + ".app"))
938
 
                            dir += "/" + command + ".app/Contents/MacOS";
939
 
#endif
940
 
#ifndef QT_NO_DIR
941
 
                        QFileInfo fileInfo( dir, command );
942
 
#else
943
 
                        QFileInfo fileInfo( dir + "/" + command );
944
 
#endif
945
 
                        if ( fileInfo.isExecutable() ) {
946
 
#if defined(Q_OS_MACX)
947
 
                            arglistQ[0] = fileInfo.absFilePath().local8Bit();
948
 
#else
949
 
                            arglistQ[0] = fileInfo.filePath().local8Bit();
950
 
#endif
951
 
                            arglist[0] = arglistQ[0];
952
 
                            break;
953
 
                        }
954
 
                    }
955
 
                }
956
 
            }
957
 
#if defined(Q_OS_MACX)
958
 
            if(!QFile::exists(arglist[0])) {
959
 
                QString command = arglist[0];
960
 
                const QString mac_bundle_suffix = ".app/Contents/MacOS/";
961
 
                if(QFile::exists(command + mac_bundle_suffix)) {
962
 
                    QString exec = command;
963
 
                    int lslash = command.findRev('/');
964
 
                    if(lslash != -1)
965
 
                        exec = command.mid(lslash+1);
966
 
                    QFileInfo fileInfo( command + mac_bundle_suffix + exec );
967
 
                    if ( fileInfo.isExecutable() ) {
968
 
                        arglistQ[0] = fileInfo.absFilePath().local8Bit();
969
 
                        arglist[0] = arglistQ[0];
970
 
                    }
971
 
                }
972
 
            }
973
 
#endif
974
 
#ifndef Q_OS_QNX4
975
 
            ::execve( arglist[0], (char*const*)arglist, (char*const*)envlist ); // ### casts not nice
976
 
#else
977
 
            ::execve( arglist[0], (char const*const*)arglist,(char const*const*)envlist ); // ### casts not nice
978
 
#endif
979
 
        }
980
 
        if ( fd[1] ) {
981
 
            char buf = 0;
982
 
            ::write( fd[1], &buf, 1 );
983
 
            ::close( fd[1] );
984
 
        }
985
 
        ::_exit( -1 );
986
 
    } else if ( pid == -1 ) {
987
 
        // error forking
988
 
        goto error;
989
 
    }
990
 
 
991
 
    // test if exec was successful
992
 
    if ( fd[1] )
993
 
        ::close( fd[1] );
994
 
    if ( fd[0] ) {
995
 
        char buf;
996
 
        for ( ;; ) {
997
 
            int n = ::read( fd[0], &buf, 1 );
998
 
            if ( n==1 ) {
999
 
                // socket was not closed => error
1000
 
                ::waitpid( pid, 0, WNOHANG );
1001
 
                d->proc = 0;
1002
 
                goto error;
1003
 
            } else if ( n==-1 ) {
1004
 
                if ( errno==EAGAIN || errno==EINTR )
1005
 
                    // try it again
1006
 
                    continue;
1007
 
            }
1008
 
            break;
1009
 
        }
1010
 
        ::close( fd[0] );
1011
 
    }
1012
 
 
1013
 
    d->newProc( pid, this );
1014
 
 
1015
 
    if ( comms & Stdin ) {
1016
 
        ::close( sStdin[0] );
1017
 
        d->proc->socketStdin = sStdin[1];
1018
 
 
1019
 
        // Select non-blocking mode
1020
 
        int originalFlags = fcntl(d->proc->socketStdin, F_GETFL, 0);
1021
 
        fcntl(d->proc->socketStdin, F_SETFL, originalFlags | O_NONBLOCK);
1022
 
 
1023
 
        d->notifierStdin = new QSocketNotifier( sStdin[1], QSocketNotifier::Write );
1024
 
        connect( d->notifierStdin, SIGNAL(activated(int)),
1025
 
                this, SLOT(socketWrite(int)) );
1026
 
        // setup notifiers for the sockets
1027
 
        if ( !d->stdinBuf.isEmpty() ) {
1028
 
            d->notifierStdin->setEnabled( TRUE );
1029
 
        }
1030
 
    }
1031
 
    if ( comms & Stdout ) {
1032
 
        ::close( sStdout[1] );
1033
 
        d->proc->socketStdout = sStdout[0];
1034
 
        d->notifierStdout = new QSocketNotifier( sStdout[0], QSocketNotifier::Read );
1035
 
        connect( d->notifierStdout, SIGNAL(activated(int)),
1036
 
                this, SLOT(socketRead(int)) );
1037
 
        if ( ioRedirection )
1038
 
            d->notifierStdout->setEnabled( TRUE );
1039
 
    }
1040
 
    if ( comms & Stderr ) {
1041
 
        ::close( sStderr[1] );
1042
 
        d->proc->socketStderr = sStderr[0];
1043
 
        d->notifierStderr = new QSocketNotifier( sStderr[0], QSocketNotifier::Read );
1044
 
        connect( d->notifierStderr, SIGNAL(activated(int)),
1045
 
                this, SLOT(socketRead(int)) );
1046
 
        if ( ioRedirection )
1047
 
            d->notifierStderr->setEnabled( TRUE );
1048
 
    }
1049
 
 
1050
 
    // cleanup and return
1051
 
    delete[] arglistQ;
1052
 
    delete[] arglist;
1053
 
    return TRUE;
1054
 
 
1055
 
error:
1056
 
#if defined(QT_QPROCESS_DEBUG)
1057
 
    qDebug( "QProcess::start(): error starting process" );
1058
 
#endif
1059
 
    if ( d->procManager )
1060
 
        d->procManager->cleanup();
1061
 
    if ( comms & Stdin ) {
1062
 
        ::close( sStdin[1] );
1063
 
        ::close( sStdin[0] );
1064
 
    }
1065
 
    if ( comms & Stdout ) {
1066
 
        ::close( sStdout[0] );
1067
 
        ::close( sStdout[1] );
1068
 
    }
1069
 
    if ( comms & Stderr ) {
1070
 
        ::close( sStderr[0] );
1071
 
        ::close( sStderr[1] );
1072
 
    }
1073
 
    ::close( fd[0] );
1074
 
    ::close( fd[1] );
1075
 
    delete[] arglistQ;
1076
 
    delete[] arglist;
1077
 
    return FALSE;
1078
 
}
1079
 
 
1080
 
 
1081
 
/*!
1082
 
    Asks the process to terminate. Processes can ignore this if they
1083
 
    wish. If you want to be certain that the process really
1084
 
    terminates, you can use kill() instead.
1085
 
 
1086
 
    The slot returns immediately: it does not wait until the process
1087
 
    has finished. When the process terminates, the processExited()
1088
 
    signal is emitted.
1089
 
 
1090
 
    \sa kill() processExited()
1091
 
*/
1092
 
void JProcess::tryTerminate() const
1093
 
{
1094
 
    if ( d->proc != 0 )
1095
 
        ::kill( d->proc->pid, SIGTERM );
1096
 
}
1097
 
 
1098
 
/*!
1099
 
    Terminates the process. This is not a safe way to end a process
1100
 
    since the process will not be able to do any cleanup.
1101
 
    tryTerminate() is safer, but processes can ignore a
1102
 
    tryTerminate().
1103
 
 
1104
 
    The nice way to end a process and to be sure that it is finished,
1105
 
    is to do something like this:
1106
 
    \code
1107
 
        process->tryTerminate();
1108
 
        QTimer::singleShot( 5000, process, SLOT( kill() ) );
1109
 
    \endcode
1110
 
 
1111
 
    This tries to terminate the process the nice way. If the process
1112
 
    is still running after 5 seconds, it terminates the process the
1113
 
    hard way. The timeout should be chosen depending on the time the
1114
 
    process needs to do all its cleanup: use a higher value if the
1115
 
    process is likely to do a lot of computation or I/O on cleanup.
1116
 
 
1117
 
    The slot returns immediately: it does not wait until the process
1118
 
    has finished. When the process terminates, the processExited()
1119
 
    signal is emitted.
1120
 
 
1121
 
    \sa tryTerminate() processExited()
1122
 
*/
1123
 
void JProcess::kill() const
1124
 
{
1125
 
    if ( d->proc != 0 )
1126
 
        ::kill( d->proc->pid, SIGKILL );
1127
 
}
1128
 
 
1129
 
/*!
1130
 
    Returns TRUE if the process is running; otherwise returns FALSE.
1131
 
 
1132
 
    \sa normalExit() exitStatus() processExited()
1133
 
*/
1134
 
bool JProcess::isRunning() const
1135
 
{
1136
 
    if ( d->exitValuesCalculated ) {
1137
 
#if defined(QT_QPROCESS_DEBUG)
1138
 
        qDebug( "QProcess::isRunning(): FALSE (already computed)" );
1139
 
#endif
1140
 
        return FALSE;
1141
 
    }
1142
 
    if ( d->proc == 0 )
1143
 
        return FALSE;
1144
 
    int status;
1145
 
    if ( ::waitpid( d->proc->pid, &status, WNOHANG ) == d->proc->pid )
1146
 
    {
1147
 
        // compute the exit values
1148
 
        JProcess *that = (JProcess*)this; // mutable
1149
 
        that->exitNormal = WIFEXITED( status ) != 0;
1150
 
        if ( exitNormal ) {
1151
 
            that->exitStat = (char)WEXITSTATUS( status );
1152
 
        }
1153
 
        d->exitValuesCalculated = TRUE;
1154
 
 
1155
 
        // On heavy processing, the socket notifier for the sigchild might not
1156
 
        // have found time to fire yet.
1157
 
        if ( d->procManager ) {
1158
 
            fd_set fds;
1159
 
            struct timeval tv;
1160
 
            FD_ZERO( &fds );
1161
 
            FD_SET( d->procManager->sigchldFd[1], &fds );
1162
 
            tv.tv_sec = 0;
1163
 
            tv.tv_usec = 0;
1164
 
            while ( ::select( d->procManager->sigchldFd[1]+1, &fds, 0, 0, &tv ) > 0 )
1165
 
                d->procManager->sigchldHnd( d->procManager->sigchldFd[1] );
1166
 
        }
1167
 
 
1168
 
#if defined(QT_QPROCESS_DEBUG)
1169
 
        qDebug( "QProcess::isRunning() (PID: %d): FALSE", d->proc->pid );
1170
 
#endif
1171
 
        return FALSE;
1172
 
    }
1173
 
#if defined(QT_QPROCESS_DEBUG)
1174
 
    qDebug( "QProcess::isRunning() (PID: %d): TRUE", d->proc->pid );
1175
 
#endif
1176
 
    return TRUE;
1177
 
}
1178
 
 
1179
 
/*!
1180
 
    Returns TRUE if it's possible to read an entire line of text from
1181
 
    standard output at this time; otherwise returns FALSE.
1182
 
 
1183
 
    \sa readLineStdout() canReadLineStderr()
1184
 
*/
1185
 
bool JProcess::canReadLineStdout() const
1186
 
{
1187
 
    if ( !d->proc || !d->proc->socketStdout )
1188
 
        return !d->bufStdout.isEmpty();
1189
 
 
1190
 
    JProcess *that = (JProcess*)this;
1191
 
    return that->scanNewline( TRUE, 0 );
1192
 
}
1193
 
 
1194
 
/*!
1195
 
    Returns TRUE if it's possible to read an entire line of text from
1196
 
    standard error at this time; otherwise returns FALSE.
1197
 
 
1198
 
    \sa readLineStderr() canReadLineStdout()
1199
 
*/
1200
 
bool JProcess::canReadLineStderr() const
1201
 
{
1202
 
    if ( !d->proc || !d->proc->socketStderr )
1203
 
        return !d->bufStderr.isEmpty();
1204
 
 
1205
 
    JProcess *that = (JProcess*)this;
1206
 
    return that->scanNewline( FALSE, 0 );
1207
 
}
1208
 
 
1209
 
/*!
1210
 
    Writes the data \a buf to the process's standard input. The
1211
 
    process may or may not read this data.
1212
 
 
1213
 
    This function returns immediately; the QProcess class might write
1214
 
    the data at a later point (you must enter the event loop for this
1215
 
    to occur). When all the data is written to the process, the signal
1216
 
    wroteToStdin() is emitted. This does not mean that the process
1217
 
    actually read the data, since this class only detects when it was
1218
 
    able to write the data to the operating system.
1219
 
 
1220
 
    \sa wroteToStdin() closeStdin() readStdout() readStderr()
1221
 
*/
1222
 
void JProcess::writeToStdin( const QByteArray& buf )
1223
 
{
1224
 
#if defined(QT_QPROCESS_DEBUG)
1225
 
//    qDebug( "QProcess::writeToStdin(): write to stdin (%d)", d->socketStdin );
1226
 
#endif
1227
 
    d->stdinBuf.enqueue( new QByteArray(buf) );
1228
 
    if ( d->notifierStdin != 0 )
1229
 
        d->notifierStdin->setEnabled( TRUE );
1230
 
}
1231
 
 
1232
 
 
1233
 
/*!
1234
 
    Closes the process's standard input.
1235
 
 
1236
 
    This function also deletes any pending data that has not been
1237
 
    written to standard input.
1238
 
 
1239
 
    \sa wroteToStdin()
1240
 
*/
1241
 
void JProcess::closeStdin()
1242
 
{
1243
 
    if ( d->proc == 0 )
1244
 
        return;
1245
 
    if ( d->proc->socketStdin !=0 ) {
1246
 
        while ( !d->stdinBuf.isEmpty() ) {
1247
 
            delete d->stdinBuf.dequeue();
1248
 
        }
1249
 
        delete d->notifierStdin;
1250
 
        d->notifierStdin = 0;
1251
 
        if ( ::close( d->proc->socketStdin ) != 0 ) {
1252
 
            qWarning( "Could not close stdin of child process" );
1253
 
        }
1254
 
#if defined(QT_QPROCESS_DEBUG)
1255
 
        qDebug( "QProcess::closeStdin(): stdin (%d) closed", d->proc->socketStdin );
1256
 
#endif
1257
 
        d->proc->socketStdin = 0;
1258
 
    }
1259
 
}
1260
 
 
1261
 
 
1262
 
/*
1263
 
  This private slot is called when the process has outputted data to either
1264
 
  standard output or standard error.
1265
 
*/
1266
 
void JProcess::socketRead( int fd )
1267
 
{
1268
 
    if ( d->socketReadCalled ) {
1269
 
        // the slots that are connected to the readyRead...() signals might
1270
 
        // trigger a recursive call of socketRead(). Avoid this since you get a
1271
 
        // blocking read otherwise.
1272
 
        return;
1273
 
    }
1274
 
 
1275
 
#if defined(QT_QPROCESS_DEBUG)
1276
 
    qDebug( "QProcess::socketRead(): %d", fd );
1277
 
#endif
1278
 
    if ( fd == 0 )
1279
 
        return;
1280
 
    const int bufsize = 4096;
1281
 
    QByteArray *buffer = 0;
1282
 
    uint oldSize;
1283
 
    int n;
1284
 
    if ( fd == d->proc->socketStdout ) {
1285
 
        buffer = &d->bufStdout;
1286
 
    } else if ( fd == d->proc->socketStderr ) {
1287
 
        buffer = &d->bufStderr;
1288
 
    } else {
1289
 
        // this case should never happen, but just to be safe
1290
 
        return;
1291
 
    }
1292
 
 
1293
 
    // try to read data first (if it fails, the filedescriptor was closed)
1294
 
    oldSize = buffer->size();
1295
 
    buffer->resize( oldSize + bufsize );
1296
 
    n = ::read( fd, buffer->data()+oldSize, bufsize );
1297
 
    if ( n > 0 )
1298
 
        buffer->resize( oldSize + n );
1299
 
    else
1300
 
        buffer->resize( oldSize );
1301
 
    // eof or error?
1302
 
    if ( n == 0 || n == -1 ) {
1303
 
        if ( fd == d->proc->socketStdout ) {
1304
 
#if defined(QT_QPROCESS_DEBUG)
1305
 
            qDebug( "QProcess::socketRead(): stdout (%d) closed", fd );
1306
 
#endif
1307
 
            d->notifierStdout->setEnabled( FALSE );
1308
 
            delete d->notifierStdout;
1309
 
            d->notifierStdout = 0;
1310
 
            ::close( d->proc->socketStdout );
1311
 
            d->proc->socketStdout = 0;
1312
 
            return;
1313
 
        } else if ( fd == d->proc->socketStderr ) {
1314
 
#if defined(QT_QPROCESS_DEBUG)
1315
 
            qDebug( "QProcess::socketRead(): stderr (%d) closed", fd );
1316
 
#endif
1317
 
            d->notifierStderr->setEnabled( FALSE );
1318
 
            delete d->notifierStderr;
1319
 
            d->notifierStderr = 0;
1320
 
            ::close( d->proc->socketStderr );
1321
 
            d->proc->socketStderr = 0;
1322
 
            return;
1323
 
        }
1324
 
    }
1325
 
 
1326
 
    fd_set fds;
1327
 
    struct timeval tv;
1328
 
    FD_ZERO( &fds );
1329
 
    FD_SET( fd, &fds );
1330
 
    tv.tv_sec = 0;
1331
 
    tv.tv_usec = 0;
1332
 
    while ( ::select( fd+1, &fds, 0, 0, &tv ) > 0 ) {
1333
 
        // prepare for the next round
1334
 
        FD_ZERO( &fds );
1335
 
        FD_SET( fd, &fds );
1336
 
        // read data
1337
 
        oldSize = buffer->size();
1338
 
        buffer->resize( oldSize + bufsize );
1339
 
        n = ::read( fd, buffer->data()+oldSize, bufsize );
1340
 
        if ( n > 0 ) {
1341
 
            buffer->resize( oldSize + n );
1342
 
        } else {
1343
 
            buffer->resize( oldSize );
1344
 
            break;
1345
 
        }
1346
 
    }
1347
 
 
1348
 
    d->socketReadCalled = TRUE;
1349
 
    if ( fd == d->proc->socketStdout ) {
1350
 
#if defined(QT_QPROCESS_DEBUG)
1351
 
        qDebug( "QProcess::socketRead(): %d bytes read from stdout (%d)",
1352
 
                buffer->size()-oldSize, fd );
1353
 
#endif
1354
 
        emit readyReadStdout();
1355
 
    } else if ( fd == d->proc->socketStderr ) {
1356
 
#if defined(QT_QPROCESS_DEBUG)
1357
 
        qDebug( "QProcess::socketRead(): %d bytes read from stderr (%d)",
1358
 
                buffer->size()-oldSize, fd );
1359
 
#endif
1360
 
        emit readyReadStderr();
1361
 
    }
1362
 
    d->socketReadCalled = FALSE;
1363
 
}
1364
 
 
1365
 
 
1366
 
/*
1367
 
  This private slot is called when the process tries to read data from standard
1368
 
  input.
1369
 
*/
1370
 
void JProcess::socketWrite( int fd )
1371
 
{
1372
 
    while ( fd == d->proc->socketStdin && d->proc->socketStdin != 0 ) {
1373
 
        if ( d->stdinBuf.isEmpty() ) {
1374
 
            d->notifierStdin->setEnabled( FALSE );
1375
 
            return;
1376
 
        }
1377
 
        ssize_t ret = ::write( fd,
1378
 
                d->stdinBuf.head()->data() + d->stdinBufRead,
1379
 
                d->stdinBuf.head()->size() - d->stdinBufRead );
1380
 
#if defined(QT_QPROCESS_DEBUG)
1381
 
        qDebug( "QProcess::socketWrite(): wrote %d bytes to stdin (%d)", ret, fd );
1382
 
#endif
1383
 
        if ( ret == -1 )
1384
 
            return;
1385
 
        d->stdinBufRead += ret;
1386
 
        if ( d->stdinBufRead == (ssize_t)d->stdinBuf.head()->size() ) {
1387
 
            d->stdinBufRead = 0;
1388
 
            delete d->stdinBuf.dequeue();
1389
 
            if ( wroteToStdinConnected && d->stdinBuf.isEmpty() )
1390
 
                emit wroteToStdin();
1391
 
        }
1392
 
    }
1393
 
}
1394
 
 
1395
 
/*!
1396
 
  \internal
1397
 
  Flushes standard input. This is useful if you want to use QProcess in a
1398
 
  synchronous manner.
1399
 
 
1400
 
  This function should probably go into the public API.
1401
 
*/
1402
 
void JProcess::flushStdin()
1403
 
{
1404
 
    socketWrite( d->proc->socketStdin );
1405
 
}
1406
 
 
1407
 
/*
1408
 
  This private slot is only used under Windows (but moc does not know about #if
1409
 
  defined()).
1410
 
*/
1411
 
void JProcess::timeout()
1412
 
{
1413
 
}
1414
 
 
1415
 
 
1416
 
/*
1417
 
  This private function is used by connectNotify() and disconnectNotify() to
1418
 
  change the value of ioRedirection (and related behaviour)
1419
 
*/
1420
 
void JProcess::setIoRedirection( bool value )
1421
 
{
1422
 
    ioRedirection = value;
1423
 
    if ( ioRedirection ) {
1424
 
        if ( d->notifierStdout )
1425
 
            d->notifierStdout->setEnabled( TRUE );
1426
 
        if ( d->notifierStderr )
1427
 
            d->notifierStderr->setEnabled( TRUE );
1428
 
    } else {
1429
 
        if ( d->notifierStdout )
1430
 
            d->notifierStdout->setEnabled( FALSE );
1431
 
        if ( d->notifierStderr )
1432
 
            d->notifierStderr->setEnabled( FALSE );
1433
 
    }
1434
 
}
1435
 
 
1436
 
/*
1437
 
  This private function is used by connectNotify() and
1438
 
  disconnectNotify() to change the value of notifyOnExit (and related
1439
 
  behaviour)
1440
 
*/
1441
 
void JProcess::setNotifyOnExit( bool value )
1442
 
{
1443
 
    notifyOnExit = value;
1444
 
}
1445
 
 
1446
 
/*
1447
 
  This private function is used by connectNotify() and disconnectNotify() to
1448
 
  change the value of wroteToStdinConnected (and related behaviour)
1449
 
*/
1450
 
void JProcess::setWroteStdinConnected( bool value )
1451
 
{
1452
 
    wroteToStdinConnected = value;
1453
 
}
1454
 
 
1455
 
/*! \enum QProcess::PID
1456
 
  \internal
1457
 
*/
1458
 
/*!
1459
 
    Returns platform dependent information about the process. This can
1460
 
    be used together with platform specific system calls.
1461
 
 
1462
 
    Under Unix the return value is the PID of the process, or -1 if no
1463
 
    process is belongs to this object.
1464
 
 
1465
 
    Under Windows it is a pointer to the \c PROCESS_INFORMATION
1466
 
    struct, or 0 if no process is belongs to this object.
1467
 
 
1468
 
    Use of this function's return value is likely to be non-portable.
1469
 
*/
1470
 
JProcess::PID JProcess::processIdentifier()
1471
 
{
1472
 
    if ( d->proc == 0 )
1473
 
        return -1;
1474
 
    return d->proc->pid;
1475
 
}
1476
 
 
1477
 
void JProcess::setChildStartingHandler(void (*childStarting)(JProcess *))
1478
 
{
1479
 
        setCallback(childStarting, this);
1480
 
}
1481
 
 
1482
 
#endif // QT_NO_PROCESS