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