00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
#include "kprocess.h"
00026
#include "kprocctrl.h"
00027
#include "kpty.h"
00028
00029
#include <config.h>
00030
00031
#ifdef __sgi
00032
#define __svr4__
00033
#endif
00034
00035
#ifdef __osf__
00036
#define _OSF_SOURCE
00037
#include <float.h>
00038
#endif
00039
00040
#ifdef _AIX
00041
#define _ALL_SOURCE
00042
#endif
00043
00044
#ifdef Q_OS_UNIX
00045
#include <sys/socket.h>
00046
#include <sys/ioctl.h>
00047
#endif
00048
00049
#include <sys/types.h>
00050
#include <sys/time.h>
00051
#include <sys/resource.h>
00052
#include <sys/stat.h>
00053
#include <sys/wait.h>
00054
00055
#ifdef HAVE_SYS_STROPTS_H
00056
#include <sys/stropts.h>
00057
#define _NEW_TTY_CTRL
00058
#endif
00059
#ifdef HAVE_SYS_SELECT_H
00060
#include <sys/select.h>
00061
#endif
00062
00063
#include <errno.h>
00064
#include <assert.h>
00065
#include <fcntl.h>
00066
#include <time.h>
00067
#include <stdlib.h>
00068
#include <signal.h>
00069
#include <stdio.h>
00070
#include <string.h>
00071
#include <unistd.h>
00072
#include <pwd.h>
00073
#include <grp.h>
00074
00075
#include <qfile.h>
00076
#include <qsocketnotifier.h>
00077
#include <qapplication.h>
00078
00079
#include <kdebug.h>
00080
#include <kstandarddirs.h>
00081
#include <kuser.h>
00082
00083
00085
00087
00088
class KProcessPrivate {
00089
public:
00090 KProcessPrivate() :
00091 usePty(
KProcess::NoCommunication),
00092 addUtmp(false), useShell(false),
00093 #ifdef Q_OS_UNIX
00094 pty(0),
00095 #endif
00096 priority(0)
00097 {
00098 }
00099
00100
KProcess::Communication usePty;
00101
bool addUtmp : 1;
00102
bool useShell : 1;
00103
00104
#ifdef Q_OS_UNIX
00105
KPty *pty;
00106
#endif
00107
00108
int priority;
00109
00110
QMap<QString,QString> env;
00111
QString wd;
00112
QCString shell;
00113
QCString executable;
00114 };
00115
00117
00119
00120 KProcess::KProcess(
QObject* parent,
const char *name )
00121 :
QObject( parent, name ),
00122 run_mode(NotifyOnExit),
00123 runs(false),
00124 pid_(0),
00125 status(0),
00126 keepPrivs(false),
00127 innot(0),
00128 outnot(0),
00129 errnot(0),
00130 communication(NoCommunication),
00131 input_data(0),
00132 input_sent(0),
00133 input_total(0)
00134 {
00135
KProcessController::ref();
00136 KProcessController::theKProcessController->
addKProcess(
this);
00137
00138 d =
new KProcessPrivate;
00139
00140
out[0] =
out[1] = -1;
00141
in[0] =
in[1] = -1;
00142
err[0] =
err[1] = -1;
00143 }
00144
00145 KProcess::KProcess()
00146 :
QObject(),
00147 run_mode(NotifyOnExit),
00148 runs(false),
00149 pid_(0),
00150 status(0),
00151 keepPrivs(false),
00152 innot(0),
00153 outnot(0),
00154 errnot(0),
00155 communication(NoCommunication),
00156 input_data(0),
00157 input_sent(0),
00158 input_total(0)
00159 {
00160
KProcessController::ref();
00161 KProcessController::theKProcessController->
addKProcess(
this);
00162
00163 d =
new KProcessPrivate;
00164
00165
out[0] =
out[1] = -1;
00166
in[0] =
in[1] = -1;
00167
err[0] =
err[1] = -1;
00168 }
00169
00170
void
00171 KProcess::setEnvironment(
const QString &name,
const QString &value)
00172 {
00173 d->env.insert(name, value);
00174 }
00175
00176
void
00177 KProcess::setWorkingDirectory(
const QString &dir)
00178 {
00179 d->wd = dir;
00180 }
00181
00182
void
00183 KProcess::setupEnvironment()
00184 {
00185
QMap<QString,QString>::Iterator it;
00186
for(it = d->env.begin(); it != d->env.end(); ++it)
00187 {
00188 setenv(QFile::encodeName(it.key()).data(),
00189 QFile::encodeName(it.data()).data(), 1);
00190 }
00191
if (!d->wd.isEmpty())
00192 {
00193 chdir(QFile::encodeName(d->wd).data());
00194 }
00195 }
00196
00197
void
00198 KProcess::setRunPrivileged(
bool keepPrivileges)
00199 {
00200
keepPrivs = keepPrivileges;
00201 }
00202
00203
bool
00204 KProcess::runPrivileged()
const
00205
{
00206
return keepPrivs;
00207 }
00208
00209
bool
00210 KProcess::setPriority(
int prio)
00211 {
00212
#ifdef Q_OS_UNIX
00213
if (
runs) {
00214
if (setpriority(PRIO_PROCESS,
pid_, prio))
00215
return false;
00216 }
else {
00217
if (prio > 19 || prio < (geteuid() ? getpriority(PRIO_PROCESS, 0) : -20))
00218
return false;
00219 }
00220
#endif
00221
d->priority = prio;
00222
return true;
00223 }
00224
00225 KProcess::~KProcess()
00226 {
00227
if (
run_mode !=
DontCare)
00228
kill(SIGKILL);
00229
detach();
00230
00231
#ifdef Q_OS_UNIX
00232
delete d->pty;
00233
#endif
00234
delete d;
00235
00236 KProcessController::theKProcessController->
removeKProcess(
this);
00237
KProcessController::deref();
00238 }
00239
00240 void KProcess::detach()
00241 {
00242
if (
runs) {
00243 KProcessController::theKProcessController->
addProcess(
pid_);
00244
runs =
false;
00245
pid_ = 0;
00246
commClose();
00247 }
00248 }
00249
00250 void KProcess::setBinaryExecutable(
const char *filename)
00251 {
00252 d->executable = filename;
00253 }
00254
00255 bool KProcess::setExecutable(
const QString& proc)
00256 {
00257
if (
runs)
return false;
00258
00259
if (proc.isEmpty())
return false;
00260
00261
if (!
arguments.isEmpty())
00262
arguments.remove(
arguments.begin());
00263
arguments.prepend(QFile::encodeName(proc));
00264
00265
return true;
00266 }
00267
00268 KProcess &
KProcess::operator<<(
const QStringList& args)
00269 {
00270 QStringList::ConstIterator it = args.begin();
00271
for ( ; it != args.end() ; ++it )
00272
arguments.append(QFile::encodeName(*it));
00273
return *
this;
00274 }
00275
00276 KProcess &
KProcess::operator<<(
const QCString& arg)
00277 {
00278
return operator<< (arg.data());
00279 }
00280
00281 KProcess &
KProcess::operator<<(
const char* arg)
00282 {
00283
arguments.append(arg);
00284
return *
this;
00285 }
00286
00287 KProcess &
KProcess::operator<<(
const QString& arg)
00288 {
00289
arguments.append(QFile::encodeName(arg));
00290
return *
this;
00291 }
00292
00293 void KProcess::clearArguments()
00294 {
00295
arguments.clear();
00296 }
00297
00298 bool KProcess::start(RunMode runmode, Communication comm)
00299 {
00300
if (
runs) {
00301 kdDebug(175) <<
"Attempted to start an already running process" <<
endl;
00302
return false;
00303 }
00304
00305 uint n =
arguments.count();
00306
if (n == 0) {
00307 kdDebug(175) <<
"Attempted to start a process without arguments" <<
endl;
00308
return false;
00309 }
00310
#ifdef Q_OS_UNIX
00311
char **arglist;
00312
QCString shellCmd;
00313
if (d->useShell)
00314 {
00315
if (d->shell.isEmpty()) {
00316 kdDebug(175) <<
"Invalid shell specified" <<
endl;
00317
return false;
00318 }
00319
00320
for (uint i = 0; i < n; i++) {
00321 shellCmd +=
arguments[i];
00322 shellCmd +=
" ";
00323 }
00324
00325 arglist = static_cast<char **>(malloc( 4 *
sizeof(
char *)));
00326 arglist[0] = d->shell.data();
00327 arglist[1] = (
char *)
"-c";
00328 arglist[2] = shellCmd.data();
00329 arglist[3] = 0;
00330 }
00331
else
00332 {
00333 arglist = static_cast<char **>(malloc( (n + 1) *
sizeof(
char *)));
00334
for (uint i = 0; i < n; i++)
00335 arglist[i] =
arguments[i].data();
00336 arglist[n] = 0;
00337 }
00338
00339
run_mode = runmode;
00340
00341
if (!
setupCommunication(comm))
00342 {
00343 kdDebug(175) <<
"Could not setup Communication!" <<
endl;
00344 free(arglist);
00345
return false;
00346 }
00347
00348
00349
00350
#ifdef HAVE_INITGROUPS
00351
struct passwd *pw = geteuid() ? 0 : getpwuid(getuid());
00352
#endif
00353
00354
int fd[2];
00355
if (pipe(fd))
00356 fd[0] = fd[1] = -1;
00357
00358 QApplication::flushX();
00359
00360
00361
00362
00363
pid_ = fork();
00364
if (
pid_ == 0) {
00365
00366
00367 close(fd[0]);
00368
00369 fcntl(fd[1], F_SETFD, FD_CLOEXEC);
00370
00371
if (!
commSetupDoneC())
00372 kdDebug(175) <<
"Could not finish comm setup in child!" <<
endl;
00373
00374
00375
struct sigaction act;
00376 sigemptyset(&act.sa_mask);
00377 act.sa_handler = SIG_DFL;
00378 act.sa_flags = 0;
00379
for (
int sig = 1; sig < NSIG; sig++)
00380 sigaction(sig, &act, 0L);
00381
00382
if (d->priority)
00383 setpriority(PRIO_PROCESS, 0, d->priority);
00384
00385
if (!
runPrivileged())
00386 {
00387 setgid(getgid());
00388
#ifdef HAVE_INITGROUPS
00389
if (pw)
00390 initgroups(pw->pw_name, pw->pw_gid);
00391
#endif
00392
setuid(getuid());
00393 }
00394
00395
setupEnvironment();
00396
00397
if (runmode ==
DontCare || runmode ==
OwnGroup)
00398 setsid();
00399
00400
const char *executable = arglist[0];
00401
if (!d->executable.isEmpty())
00402 executable = d->executable.data();
00403 execvp(executable, arglist);
00404
00405
char resultByte = 1;
00406 write(fd[1], &resultByte, 1);
00407 _exit(-1);
00408 }
else if (
pid_ == -1) {
00409
00410
00411
00412
pid_ = 0;
00413 free(arglist);
00414
return false;
00415 }
00416
00417 free(arglist);
00418
00419
if (!
commSetupDoneP())
00420 kdDebug(175) <<
"Could not finish comm setup in parent!" <<
endl;
00421
00422
00423 close(fd[1]);
00424
for(;;)
00425 {
00426
char resultByte;
00427
int n = ::read(fd[0], &resultByte, 1);
00428
if (n == 1)
00429 {
00430
00431 close(fd[0]);
00432 waitpid(
pid_, 0, 0);
00433
pid_ = 0;
00434
commClose();
00435
return false;
00436 }
00437
if (n == -1)
00438 {
00439
if (errno == EINTR)
00440
continue;
00441 }
00442
break;
00443 }
00444 close(fd[0]);
00445
00446
runs =
true;
00447
switch (runmode)
00448 {
00449
case Block:
00450
for (;;)
00451 {
00452
commClose();
00453
if (!
runs)
00454 {
00455
00456 KProcessController::theKProcessController->
unscheduleCheck();
00457
if (waitpid(
pid_, &
status, WNOHANG) != 0)
00458 {
00459
commClose();
00460 KProcessController::theKProcessController->
rescheduleCheck();
00461
break;
00462 }
00463
runs =
true;
00464 }
00465
else
00466 {
00467
00468
00469
00470 waitpid(
pid_, &
status, 0);
00471
runs =
false;
00472
break;
00473 }
00474 }
00475
00476
00477 emit
processExited(
this);
00478
break;
00479
default:
00480
input_data = 0;
00481
break;
00482 }
00483
return true;
00484
#else
00485
00486
return false;
00487
#endif
00488
}
00489
00490
00491
00492 bool KProcess::kill(
int signo)
00493 {
00494
#ifdef Q_OS_UNIX
00495
if (
runs &&
pid_ > 0 && !::kill(
run_mode ==
OwnGroup ? -
pid_ :
pid_, signo))
00496
return true;
00497
#endif
00498
return false;
00499 }
00500
00501
00502
00503 bool KProcess::isRunning()
const
00504
{
00505
return runs;
00506 }
00507
00508
00509
00510 pid_t
KProcess::pid()
const
00511
{
00512
return pid_;
00513 }
00514
00515
#ifndef timersub
00516
# define timersub(a, b, result) \
00517
do { \
00518
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
00519
(result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
00520
if ((result)->tv_usec < 0) { \
00521
--(result)->tv_sec; \
00522
(result)->tv_usec += 1000000; \
00523
} \
00524
} while (0)
00525
#endif
00526
00527 bool KProcess::wait(
int timeout)
00528 {
00529
if (!
runs)
00530
return true;
00531
00532
#ifndef __linux__
00533
struct timeval etv;
00534
#endif
00535
struct timeval tv, *tvp;
00536
if (timeout < 0)
00537 tvp = 0;
00538
else
00539 {
00540
#ifndef __linux__
00541
gettimeofday(&etv, 0);
00542 etv.tv_sec += timeout;
00543
#else
00544
tv.tv_sec = timeout;
00545 tv.tv_usec = 0;
00546
#endif
00547
tvp = &tv;
00548 }
00549
00550
#ifdef Q_OS_UNIX
00551
int fd = KProcessController::theKProcessController->
notifierFd();
00552
for(;;)
00553 {
00554 fd_set fds;
00555 FD_ZERO( &fds );
00556 FD_SET( fd, &fds );
00557
00558
#ifndef __linux__
00559
if (tvp)
00560 {
00561 gettimeofday(&tv, 0);
00562 timersub(&etv, &tv, &tv);
00563
if (tv.tv_sec < 0)
00564 tv.tv_sec = tv.tv_usec = 0;
00565 }
00566
#endif
00567
00568
switch( select( fd+1, &fds, 0, 0, tvp ) )
00569 {
00570
case -1:
00571
if( errno == EINTR )
00572
break;
00573
00574
case 0:
00575 KProcessController::theKProcessController->
rescheduleCheck();
00576
return false;
00577
default:
00578 KProcessController::theKProcessController->
unscheduleCheck();
00579
if (waitpid(
pid_, &
status, WNOHANG) != 0)
00580 {
00581
processHasExited(
status);
00582 KProcessController::theKProcessController->
rescheduleCheck();
00583
return true;
00584 }
00585 }
00586 }
00587
#endif //Q_OS_UNIX
00588
return false;
00589 }
00590
00591
00592
00593 bool KProcess::normalExit()
const
00594
{
00595
return (
pid_ != 0) && !
runs && WIFEXITED(
status);
00596 }
00597
00598
00599 bool KProcess::signalled()
const
00600
{
00601
return (
pid_ != 0) && !
runs && WIFSIGNALED(
status);
00602 }
00603
00604
00605 bool KProcess::coreDumped()
const
00606
{
00607
#ifdef WCOREDUMP
00608
return signalled() && WCOREDUMP(
status);
00609
#else
00610
return false;
00611
#endif
00612
}
00613
00614
00615 int KProcess::exitStatus()
const
00616
{
00617
return WEXITSTATUS(
status);
00618 }
00619
00620
00621 int KProcess::exitSignal()
const
00622
{
00623
return WTERMSIG(
status);
00624 }
00625
00626
00627 bool KProcess::writeStdin(
const char *buffer,
int buflen)
00628 {
00629
00630
00631
00632
if (
input_data != 0)
00633
return false;
00634
00635
if (
communication & Stdin) {
00636
input_data = buffer;
00637
input_sent = 0;
00638
input_total = buflen;
00639
innot->setEnabled(
true);
00640
if (
input_total)
00641
slotSendData(0);
00642
return true;
00643 }
else
00644
return false;
00645 }
00646
00647 void KProcess::suspend()
00648 {
00649
if (
outnot)
00650
outnot->setEnabled(
false);
00651 }
00652
00653 void KProcess::resume()
00654 {
00655
if (
outnot)
00656
outnot->setEnabled(
true);
00657 }
00658
00659 bool KProcess::closeStdin()
00660 {
00661
if (
communication & Stdin) {
00662
communication = (
Communication) (
communication & ~Stdin);
00663
delete innot;
00664
innot = 0;
00665
if (!(d->usePty & Stdin))
00666 close(
in[1]);
00667
in[1] = -1;
00668
return true;
00669 }
else
00670
return false;
00671 }
00672
00673 bool KProcess::closeStdout()
00674 {
00675
if (
communication & Stdout) {
00676
communication = (
Communication) (
communication & ~Stdout);
00677
delete outnot;
00678
outnot = 0;
00679
if (!(d->usePty & Stdout))
00680 close(
out[0]);
00681
out[0] = -1;
00682
return true;
00683 }
else
00684
return false;
00685 }
00686
00687 bool KProcess::closeStderr()
00688 {
00689
if (
communication & Stderr) {
00690
communication = (
Communication) (
communication & ~Stderr);
00691
delete errnot;
00692
errnot = 0;
00693
if (!(d->usePty & Stderr))
00694 close(
err[0]);
00695
err[0] = -1;
00696
return true;
00697 }
else
00698
return false;
00699 }
00700
00701 bool KProcess::closePty()
00702 {
00703
#ifdef Q_OS_UNIX
00704
if (d->pty && d->pty->masterFd() >= 0) {
00705
if (d->addUtmp)
00706 d->pty->logout();
00707 d->pty->close();
00708
return true;
00709 }
else
00710
return false;
00711
#else
00712
return false;
00713
#endif
00714
}
00715
00716 void KProcess::closeAll()
00717 {
00718
closeStdin();
00719
closeStdout();
00720
closeStderr();
00721
closePty();
00722 }
00723
00725
00727
00728
00729
00730 void KProcess::slotChildOutput(
int fdno)
00731 {
00732
if (!
childOutput(fdno))
00733
closeStdout();
00734 }
00735
00736
00737 void KProcess::slotChildError(
int fdno)
00738 {
00739
if (!
childError(fdno))
00740
closeStderr();
00741 }
00742
00743
00744 void KProcess::slotSendData(
int)
00745 {
00746
if (
input_sent ==
input_total) {
00747
innot->setEnabled(
false);
00748
input_data = 0;
00749 emit
wroteStdin(
this);
00750 }
else {
00751
int result = ::write(
in[1],
input_data+
input_sent,
input_total-input_sent);
00752
if (result >= 0)
00753 {
00754 input_sent += result;
00755 }
00756
else if ((errno != EAGAIN) && (errno != EINTR))
00757 {
00758 kdDebug(175) <<
"Error writing to stdin of child process" <<
endl;
00759
closeStdin();
00760 }
00761 }
00762 }
00763
00764 void KProcess::setUseShell(
bool useShell,
const char *shell)
00765 {
00766 d->useShell = useShell;
00767
if (shell && *shell)
00768 d->shell = shell;
00769
else
00770
00771
#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__GNU__)
00772
00773
if (!access(
"/usr/xpg4/bin/sh", X_OK ))
00774 d->shell =
"/usr/xpg4/bin/sh";
00775
else
00776
00777
if (!access(
"/bin/ksh", X_OK ))
00778 d->shell =
"/bin/ksh";
00779
else
00780
00781
if (!access(
"/usr/ucb/sh", X_OK ))
00782 d->shell =
"/usr/ucb/sh";
00783
else
00784
#endif
00785
d->shell =
"/bin/sh";
00786 }
00787
00788
#ifdef Q_OS_UNIX
00789
void KProcess::setUsePty(Communication usePty,
bool addUtmp)
00790 {
00791 d->usePty = usePty;
00792 d->addUtmp = addUtmp;
00793
if (usePty) {
00794
if (!d->pty)
00795 d->pty =
new KPty;
00796 }
else {
00797
delete d->pty;
00798 d->pty = 0;
00799 }
00800 }
00801
00802 KPty *KProcess::pty()
const
00803
{
00804
return d->pty;
00805 }
00806
#endif //Q_OS_UNIX
00807
00808 QString KProcess::quote(
const QString &arg)
00809 {
00810
QChar q(
'\'');
00811
return QString(arg).replace(q,
"'\\''").prepend(q).append(q);
00812 }
00813
00814
00816
00818
00819
00820 void KProcess::processHasExited(
int state)
00821 {
00822
00823
00824
status = state;
00825
runs =
false;
00826
00827
commClose();
00828
00829
if (
run_mode !=
DontCare)
00830 emit
processExited(
this);
00831 }
00832
00833
00834
00835 int KProcess::childOutput(
int fdno)
00836 {
00837
if (
communication & NoRead) {
00838
int len = -1;
00839 emit
receivedStdout(fdno, len);
00840 errno = 0;
00841
return len;
00842 }
00843
else
00844 {
00845
char buffer[1025];
00846
int len;
00847
00848 len = ::read(fdno, buffer, 1024);
00849
00850
if (len > 0) {
00851 buffer[len] = 0;
00852 emit
receivedStdout(
this, buffer, len);
00853 }
00854
return len;
00855 }
00856 }
00857
00858 int KProcess::childError(
int fdno)
00859 {
00860
char buffer[1025];
00861
int len;
00862
00863 len = ::read(fdno, buffer, 1024);
00864
00865
if (len > 0) {
00866 buffer[len] = 0;
00867 emit
receivedStderr(
this, buffer, len);
00868 }
00869
return len;
00870 }
00871
00872
00873 int KProcess::setupCommunication(Communication comm)
00874 {
00875
#ifdef Q_OS_UNIX
00876
00877
if (d->usePty)
00878 {
00879
00880
if (!(~(comm & d->usePty) & (Stdout | Stderr))) {
00881 kdWarning(175) <<
"Invalid usePty/communication combination (" << d->usePty <<
"/" << comm <<
")" <<
endl;
00882
return 0;
00883 }
00884
if (!d->pty->open())
00885
return 0;
00886
00887
int rcomm = comm & d->usePty;
00888
int mfd = d->pty->masterFd();
00889
if (rcomm & Stdin)
00890
in[1] = mfd;
00891
if (rcomm & Stdout)
00892
out[0] = mfd;
00893
if (rcomm & Stderr)
00894
err[0] = mfd;
00895 }
00896
00897
communication = comm;
00898
00899 comm = (
Communication) (comm & ~d->usePty);
00900
if (comm & Stdin) {
00901
if (socketpair(AF_UNIX, SOCK_STREAM, 0,
in))
00902
goto fail0;
00903 fcntl(
in[0], F_SETFD, FD_CLOEXEC);
00904 fcntl(
in[1], F_SETFD, FD_CLOEXEC);
00905 }
00906
if (comm & Stdout) {
00907
if (socketpair(AF_UNIX, SOCK_STREAM, 0,
out))
00908
goto fail1;
00909 fcntl(
out[0], F_SETFD, FD_CLOEXEC);
00910 fcntl(
out[1], F_SETFD, FD_CLOEXEC);
00911 }
00912
if (comm & Stderr) {
00913
if (socketpair(AF_UNIX, SOCK_STREAM, 0,
err))
00914
goto fail2;
00915 fcntl(
err[0], F_SETFD, FD_CLOEXEC);
00916 fcntl(
err[1], F_SETFD, FD_CLOEXEC);
00917 }
00918
return 1;
00919 fail2:
00920
if (comm & Stdout)
00921 {
00922 close(
out[0]);
00923 close(
out[1]);
00924
out[0] =
out[1] = -1;
00925 }
00926 fail1:
00927
if (comm & Stdin)
00928 {
00929 close(
in[0]);
00930 close(
in[1]);
00931
in[0] =
in[1] = -1;
00932 }
00933 fail0:
00934
communication = NoCommunication;
00935
#endif //Q_OS_UNIX
00936
return 0;
00937 }
00938
00939
00940
00941 int KProcess::commSetupDoneP()
00942 {
00943
int rcomm =
communication & ~d->usePty;
00944
if (rcomm & Stdin)
00945 close(
in[0]);
00946
if (rcomm & Stdout)
00947 close(
out[1]);
00948
if (rcomm & Stderr)
00949 close(
err[1]);
00950
in[0] =
out[1] =
err[1] = -1;
00951
00952
00953
if (
run_mode !=
NotifyOnExit &&
run_mode !=
OwnGroup)
00954
return 1;
00955
00956
if (
communication & Stdin) {
00957 fcntl(
in[1], F_SETFL, O_NONBLOCK | fcntl(
in[1], F_GETFL));
00958
innot =
new QSocketNotifier(in[1], QSocketNotifier::Write,
this);
00959 Q_CHECK_PTR(
innot);
00960
innot->setEnabled(
false);
00961 QObject::connect(
innot, SIGNAL(activated(
int)),
00962
this, SLOT(
slotSendData(
int)));
00963 }
00964
00965
if (
communication & Stdout) {
00966
outnot =
new QSocketNotifier(out[0], QSocketNotifier::Read,
this);
00967 Q_CHECK_PTR(
outnot);
00968 QObject::connect(
outnot, SIGNAL(activated(
int)),
00969
this, SLOT(
slotChildOutput(
int)));
00970
if (
communication & NoRead)
00971
suspend();
00972 }
00973
00974
if (
communication & Stderr) {
00975
errnot =
new QSocketNotifier(err[0], QSocketNotifier::Read,
this );
00976 Q_CHECK_PTR(
errnot);
00977 QObject::connect(
errnot, SIGNAL(activated(
int)),
00978
this, SLOT(
slotChildError(
int)));
00979 }
00980
00981
return 1;
00982 }
00983
00984
00985
00986 int KProcess::commSetupDoneC()
00987 {
00988
int ok = 1;
00989
#ifdef Q_OS_UNIX
00990
00991
if (d->usePty & Stdin) {
00992
if (dup2(d->pty->slaveFd(), STDIN_FILENO) < 0) ok = 0;
00993 }
else if (
communication & Stdin) {
00994
if (dup2(
in[0], STDIN_FILENO) < 0) ok = 0;
00995 }
else {
00996
int null_fd = open(
"/dev/null", O_RDONLY );
00997
if (dup2( null_fd, STDIN_FILENO ) < 0) ok = 0;
00998 close( null_fd );
00999 }
01000
struct linger so;
01001 memset(&so, 0,
sizeof(so));
01002
if (d->usePty & Stdout) {
01003
if (dup2(d->pty->slaveFd(), STDOUT_FILENO) < 0) ok = 0;
01004 }
else if (
communication & Stdout) {
01005
if (dup2(
out[1], STDOUT_FILENO) < 0 ||
01006 setsockopt(
out[1], SOL_SOCKET, SO_LINGER, (
char *)&so,
sizeof(so)))
01007 ok = 0;
01008 }
01009
if (d->usePty & Stderr) {
01010
if (dup2(d->pty->slaveFd(), STDERR_FILENO) < 0) ok = 0;
01011 }
else if (
communication & Stderr) {
01012
if (dup2(
err[1], STDERR_FILENO) < 0 ||
01013 setsockopt(
err[1], SOL_SOCKET, SO_LINGER, (
char *)&so,
sizeof(so)))
01014 ok = 0;
01015 }
01016
01017
01018
01019
01020
if (d->usePty) {
01021 d->pty->setCTty();
01022
if (d->addUtmp)
01023 d->pty->login(
KUser(KUser::UseRealUserID).loginName().local8Bit().data(), getenv(
"DISPLAY"));
01024 }
01025
#endif //Q_OS_UNIX
01026
01027
return ok;
01028 }
01029
01030
01031
01032 void KProcess::commClose()
01033 {
01034
closeStdin();
01035
01036
#ifdef Q_OS_UNIX
01037
if (
pid_) {
01038
01039
01040
01041
01042
int notfd = KProcessController::theKProcessController->
notifierFd();
01043
01044
while ((
communication & (Stdout | Stderr)) ||
runs) {
01045 fd_set rfds;
01046 FD_ZERO(&rfds);
01047
struct timeval timeout, *p_timeout;
01048
01049
int max_fd = 0;
01050
if (
communication & Stdout) {
01051 FD_SET(
out[0], &rfds);
01052 max_fd =
out[0];
01053 }
01054
if (
communication & Stderr) {
01055 FD_SET(
err[0], &rfds);
01056
if (
err[0] > max_fd)
01057 max_fd =
err[0];
01058 }
01059
if (
runs) {
01060 FD_SET(notfd, &rfds);
01061
if (notfd > max_fd)
01062 max_fd = notfd;
01063
01064
01065 p_timeout = 0;
01066 }
else {
01067
01068
01069 timeout.tv_sec = timeout.tv_usec = 0;
01070 p_timeout = &timeout;
01071 }
01072
01073
int fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout);
01074
if (fds_ready < 0) {
01075
if (errno == EINTR)
01076
continue;
01077
break;
01078 }
else if (!fds_ready)
01079
break;
01080
01081
if ((
communication & Stdout) && FD_ISSET(
out[0], &rfds))
01082
slotChildOutput(
out[0]);
01083
01084
if ((
communication & Stderr) && FD_ISSET(
err[0], &rfds))
01085
slotChildError(
err[0]);
01086
01087
if (
runs && FD_ISSET(notfd, &rfds)) {
01088
runs =
false;
01089
return;
01090 }
01091 }
01092 }
01093
#endif //Q_OS_UNIX
01094
01095
closeStdout();
01096
closeStderr();
01097
01098
closePty();
01099 }
01100
01101
01102
void KProcess::virtual_hook(
int,
void* )
01103 { }
01104
01105
01107
01109
01110 KShellProcess::KShellProcess(
const char *shellname):
01111
KProcess()
01112 {
01113 setUseShell(
true, shellname ? shellname : getenv(
"SHELL") );
01114 }
01115
01116 KShellProcess::~KShellProcess() {
01117 }
01118
01119 QString KShellProcess::quote(
const QString &arg)
01120 {
01121
return KProcess::quote(arg);
01122 }
01123
01124 bool KShellProcess::start(RunMode runmode, Communication comm)
01125 {
01126
return KProcess::start(runmode, comm);
01127 }
01128
01129
void KShellProcess::virtual_hook(
int id,
void* data )
01130 { KProcess::virtual_hook(
id, data ); }
01131
01132
#include "kprocess.moc"