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 if (shell && *shell)
00743 d->shell = shell;
00744 else
00745
00746 #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__GNU__)
00747
00748 if (!access( "/usr/xpg4/bin/sh", X_OK ))
00749 d->shell = "/usr/xpg4/bin/sh";
00750 else
00751
00752 if (!access( "/bin/ksh", X_OK ))
00753 d->shell = "/bin/ksh";
00754 else
00755
00756 if (!access( "/usr/ucb/sh", X_OK ))
00757 d->shell = "/usr/ucb/sh";
00758 else
00759 #endif
00760 d->shell = "/bin/sh";
00761 }
00762
00763 void KProcess::setUsePty(Communication usePty, bool addUtmp)
00764 {
00765 d->usePty = usePty;
00766 d->addUtmp = addUtmp;
00767 if (usePty) {
00768 if (!d->pty)
00769 d->pty = new KPty;
00770 } else {
00771 delete d->pty;
00772 d->pty = 0;
00773 }
00774 }
00775
00776 KPty *KProcess::pty() const
00777 {
00778 return d->pty;
00779 }
00780
00781 QString KProcess::quote(const QString &arg)
00782 {
00783 QChar q('\'');
00784 return QString(arg).replace(q, "'\\''").prepend(q).append(q);
00785 }
00786
00787
00789
00791
00792
00793 void KProcess::processHasExited(int state)
00794 {
00795
00796
00797 status = state;
00798 runs = false;
00799
00800 commClose();
00801
00802 if (run_mode != DontCare)
00803 emit processExited(this);
00804 }
00805
00806
00807
00808 int KProcess::childOutput(int fdno)
00809 {
00810 if (communication & NoRead) {
00811 int len = -1;
00812 emit receivedStdout(fdno, len);
00813 errno = 0;
00814 return len;
00815 }
00816 else
00817 {
00818 char buffer[1025];
00819 int len;
00820
00821 len = ::read(fdno, buffer, 1024);
00822
00823 if (len > 0) {
00824 buffer[len] = 0;
00825 emit receivedStdout(this, buffer, len);
00826 }
00827 return len;
00828 }
00829 }
00830
00831 int KProcess::childError(int fdno)
00832 {
00833 char buffer[1025];
00834 int len;
00835
00836 len = ::read(fdno, buffer, 1024);
00837
00838 if (len > 0) {
00839 buffer[len] = 0;
00840 emit receivedStderr(this, buffer, len);
00841 }
00842 return len;
00843 }
00844
00845
00846 int KProcess::setupCommunication(Communication comm)
00847 {
00848
00849 if (d->usePty)
00850 {
00851
00852 if (!(~(comm & d->usePty) & (Stdout | Stderr))) {
00853 kdWarning(175) << "Invalid usePty/communication combination (" << d->usePty << "/" << comm << ")" << endl;
00854 return 0;
00855 }
00856 if (!d->pty->open())
00857 return 0;
00858
00859 int rcomm = comm & d->usePty;
00860 int mfd = d->pty->masterFd();
00861 if (rcomm & Stdin)
00862 in[1] = mfd;
00863 if (rcomm & Stdout)
00864 out[0] = mfd;
00865 if (rcomm & Stderr)
00866 err[0] = mfd;
00867 }
00868
00869 communication = comm;
00870
00871 comm = (Communication) (comm & ~d->usePty);
00872 if (comm & Stdin) {
00873 if (socketpair(AF_UNIX, SOCK_STREAM, 0, in))
00874 goto fail0;
00875 fcntl(in[0], F_SETFD, FD_CLOEXEC);
00876 fcntl(in[1], F_SETFD, FD_CLOEXEC);
00877 }
00878 if (comm & Stdout) {
00879 if (socketpair(AF_UNIX, SOCK_STREAM, 0, out))
00880 goto fail1;
00881 fcntl(out[0], F_SETFD, FD_CLOEXEC);
00882 fcntl(out[1], F_SETFD, FD_CLOEXEC);
00883 }
00884 if (comm & Stderr) {
00885 if (socketpair(AF_UNIX, SOCK_STREAM, 0, err))
00886 goto fail2;
00887 fcntl(err[0], F_SETFD, FD_CLOEXEC);
00888 fcntl(err[1], F_SETFD, FD_CLOEXEC);
00889 }
00890 return 1;
00891 fail2:
00892 if (comm & Stdout)
00893 {
00894 close(out[0]);
00895 close(out[1]);
00896 out[0] = out[1] = -1;
00897 }
00898 fail1:
00899 if (comm & Stdin)
00900 {
00901 close(in[0]);
00902 close(in[1]);
00903 in[0] = in[1] = -1;
00904 }
00905 fail0:
00906 communication = NoCommunication;
00907 return 0;
00908 }
00909
00910
00911
00912 int KProcess::commSetupDoneP()
00913 {
00914 int rcomm = communication & ~d->usePty;
00915 if (rcomm & Stdin)
00916 close(in[0]);
00917 if (rcomm & Stdout)
00918 close(out[1]);
00919 if (rcomm & Stderr)
00920 close(err[1]);
00921 in[0] = out[1] = err[1] = -1;
00922
00923
00924 if (run_mode != NotifyOnExit && run_mode != OwnGroup)
00925 return 1;
00926
00927 if (communication & Stdin) {
00928 fcntl(in[1], F_SETFL, O_NONBLOCK | fcntl(in[1], F_GETFL));
00929 innot = new QSocketNotifier(in[1], QSocketNotifier::Write, this);
00930 Q_CHECK_PTR(innot);
00931 innot->setEnabled(false);
00932 QObject::connect(innot, SIGNAL(activated(int)),
00933 this, SLOT(slotSendData(int)));
00934 }
00935
00936 if (communication & Stdout) {
00937 outnot = new QSocketNotifier(out[0], QSocketNotifier::Read, this);
00938 Q_CHECK_PTR(outnot);
00939 QObject::connect(outnot, SIGNAL(activated(int)),
00940 this, SLOT(slotChildOutput(int)));
00941 if (communication & NoRead)
00942 suspend();
00943 }
00944
00945 if (communication & Stderr) {
00946 errnot = new QSocketNotifier(err[0], QSocketNotifier::Read, this );
00947 Q_CHECK_PTR(errnot);
00948 QObject::connect(errnot, SIGNAL(activated(int)),
00949 this, SLOT(slotChildError(int)));
00950 }
00951
00952 return 1;
00953 }
00954
00955
00956
00957 int KProcess::commSetupDoneC()
00958 {
00959 int ok = 1;
00960
00961 if (d->usePty & Stdin) {
00962 if (dup2(d->pty->slaveFd(), STDIN_FILENO) < 0) ok = 0;
00963 } else if (communication & Stdin) {
00964 if (dup2(in[0], STDIN_FILENO) < 0) ok = 0;
00965 } else {
00966 int null_fd = open( "/dev/null", O_RDONLY );
00967 if (dup2( null_fd, STDIN_FILENO ) < 0) ok = 0;
00968 close( null_fd );
00969 }
00970 struct linger so;
00971 memset(&so, 0, sizeof(so));
00972 if (d->usePty & Stdout) {
00973 if (dup2(d->pty->slaveFd(), STDOUT_FILENO) < 0) ok = 0;
00974 } else if (communication & Stdout) {
00975 if (dup2(out[1], STDOUT_FILENO) < 0 ||
00976 setsockopt(out[1], SOL_SOCKET, SO_LINGER, (char *)&so, sizeof(so)))
00977 ok = 0;
00978 }
00979 if (d->usePty & Stderr) {
00980 if (dup2(d->pty->slaveFd(), STDERR_FILENO) < 0) ok = 0;
00981 } else if (communication & Stderr) {
00982 if (dup2(err[1], STDERR_FILENO) < 0 ||
00983 setsockopt(err[1], SOL_SOCKET, SO_LINGER, (char *)&so, sizeof(so)))
00984 ok = 0;
00985 }
00986
00987
00988
00989
00990 if (d->usePty) {
00991 d->pty->setCTty();
00992 if (d->addUtmp)
00993 d->pty->login(KUser(KUser::UseRealUserID).loginName().local8Bit().data(), getenv("DISPLAY"));
00994 }
00995
00996 return ok;
00997 }
00998
00999
01000
01001 void KProcess::commClose()
01002 {
01003 closeStdin();
01004
01005 if (pid_) {
01006
01007
01008
01009
01010 int notfd = KProcessController::theKProcessController->notifierFd();
01011
01012 while ((communication & (Stdout | Stderr)) || runs) {
01013 fd_set rfds;
01014 FD_ZERO(&rfds);
01015 struct timeval timeout, *p_timeout;
01016
01017 int max_fd = 0;
01018 if (communication & Stdout) {
01019 FD_SET(out[0], &rfds);
01020 max_fd = out[0];
01021 }
01022 if (communication & Stderr) {
01023 FD_SET(err[0], &rfds);
01024 if (err[0] > max_fd)
01025 max_fd = err[0];
01026 }
01027 if (runs) {
01028 FD_SET(notfd, &rfds);
01029 if (notfd > max_fd)
01030 max_fd = notfd;
01031
01032
01033 p_timeout = 0;
01034 } else {
01035
01036
01037 timeout.tv_sec = timeout.tv_usec = 0;
01038 p_timeout = &timeout;
01039 }
01040
01041 int fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout);
01042 if (fds_ready < 0) {
01043 if (errno == EINTR)
01044 continue;
01045 break;
01046 } else if (!fds_ready)
01047 break;
01048
01049 if ((communication & Stdout) && FD_ISSET(out[0], &rfds))
01050 slotChildOutput(out[0]);
01051
01052 if ((communication & Stderr) && FD_ISSET(err[0], &rfds))
01053 slotChildError(err[0]);
01054
01055 if (runs && FD_ISSET(notfd, &rfds)) {
01056 runs = false;
01057 return;
01058 }
01059 }
01060 }
01061
01062 closeStdout();
01063 closeStderr();
01064
01065 closePty();
01066 }
01067
01068
01069 void KProcess::virtual_hook( int, void* )
01070 { }
01071
01072
01074
01076
01077 KShellProcess::KShellProcess(const char *shellname):
01078 KProcess()
01079 {
01080 setUseShell( true, shellname ? shellname : getenv("SHELL") );
01081 }
01082
01083 KShellProcess::~KShellProcess() {
01084 }
01085
01086 QString KShellProcess::quote(const QString &arg)
01087 {
01088 return KProcess::quote(arg);
01089 }
01090
01091 bool KShellProcess::start(RunMode runmode, Communication comm)
01092 {
01093 return KProcess::start(runmode, comm);
01094 }
01095
01096 void KShellProcess::virtual_hook( int id, void* data )
01097 { KProcess::virtual_hook( id, data ); }
01098
01099 #include "kprocess.moc"