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