~ubuntu-branches/ubuntu/jaunty/psi/jaunty

« 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: 2005-01-10 17:41:43 UTC
  • mfrom: (1.2.1 upstream) (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050110174143-ltocv5zapl6blf5d
Tags: 0.9.3-1
* New upstream release
* Cleaned up debian/rules (some things are done by upstream Makefiles now)
* Fixed some lintian warnings:
  - removed executable bit from some .png files
  - moved psi.desktop to /usr/share/applications
* Updated menu files

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