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
00359
00360
00361 pid_ = fork();
00362 if (pid_ == 0) {
00363
00364
00365 close(fd[0]);
00366
00367 fcntl(fd[1], F_SETFD, FD_CLOEXEC);
00368
00369 if (!commSetupDoneC())
00370 kdDebug(175) << "Could not finish comm setup in child!" << endl;
00371
00372
00373 struct sigaction act;
00374 sigemptyset(&act.sa_mask);
00375 act.sa_handler = SIG_DFL;
00376 act.sa_flags = 0;
00377 for (int sig = 1; sig < NSIG; sig++)
00378 sigaction(sig, &act, 0L);
00379
00380 if (d->priority)
00381 setpriority(PRIO_PROCESS, 0, d->priority);
00382
00383 if (!runPrivileged())
00384 {
00385 setgid(getgid());
00386 #ifdef HAVE_INITGROUPS
00387 if (pw)
00388 initgroups(pw->pw_name, pw->pw_gid);
00389 #endif
00390 setuid(getuid());
00391 }
00392
00393 setupEnvironment();
00394
00395 if (runmode == DontCare || runmode == OwnGroup)
00396 setsid();
00397
00398 const char *executable = arglist[0];
00399 if (!d->executable.isEmpty())
00400 executable = d->executable.data();
00401 execvp(executable, arglist);
00402
00403 char resultByte = 1;
00404 write(fd[1], &resultByte, 1);
00405 _exit(-1);
00406 } else if (pid_ == -1) {
00407
00408
00409
00410 pid_ = 0;
00411 free(arglist);
00412 return false;
00413 }
00414
00415 free(arglist);
00416
00417 if (!commSetupDoneP())
00418 kdDebug(175) << "Could not finish comm setup in parent!" << endl;
00419
00420
00421 close(fd[1]);
00422 for(;;)
00423 {
00424 char resultByte;
00425 int n = ::read(fd[0], &resultByte, 1);
00426 if (n == 1)
00427 {
00428
00429 close(fd[0]);
00430 waitpid(pid_, 0, 0);
00431 pid_ = 0;
00432 commClose();
00433 return false;
00434 }
00435 if (n == -1)
00436 {
00437 if (errno == EINTR)
00438 continue;
00439 }
00440 break;
00441 }
00442 close(fd[0]);
00443
00444 runs = true;
00445 switch (runmode)
00446 {
00447 case Block:
00448 for (;;)
00449 {
00450 commClose();
00451 if (!runs)
00452 {
00453
00454 KProcessController::theKProcessController->unscheduleCheck();
00455 if (waitpid(pid_, &status, WNOHANG) != 0)
00456 {
00457 commClose();
00458 KProcessController::theKProcessController->rescheduleCheck();
00459 break;
00460 }
00461 runs = true;
00462 }
00463 else
00464 {
00465
00466
00467
00468 waitpid(pid_, &status, 0);
00469 runs = false;
00470 break;
00471 }
00472 }
00473
00474
00475 emit processExited(this);
00476 break;
00477 default:
00478 input_data = 0;
00479 break;
00480 }
00481 return true;
00482 #else
00483
00484 return false;
00485 #endif
00486 }
00487
00488
00489
00490 bool KProcess::kill(int signo)
00491 {
00492 #ifdef Q_OS_UNIX
00493 if (runs && pid_ > 0 && !::kill(run_mode == OwnGroup ? -pid_ : pid_, signo))
00494 return true;
00495 #endif
00496 return false;
00497 }
00498
00499
00500
00501 bool KProcess::isRunning() const
00502 {
00503 return runs;
00504 }
00505
00506
00507
00508 pid_t KProcess::pid() const
00509 {
00510 return pid_;
00511 }
00512
00513 #ifndef timersub
00514 # define timersub(a, b, result) \
00515 do { \
00516 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
00517 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
00518 if ((result)->tv_usec < 0) { \
00519 --(result)->tv_sec; \
00520 (result)->tv_usec += 1000000; \
00521 } \
00522 } while (0)
00523 #endif
00524
00525 bool KProcess::wait(int timeout)
00526 {
00527 if (!runs)
00528 return true;
00529
00530 #ifndef __linux__
00531 struct timeval etv;
00532 #endif
00533 struct timeval tv, *tvp;
00534 if (timeout < 0)
00535 tvp = 0;
00536 else
00537 {
00538 #ifndef __linux__
00539 gettimeofday(&etv, 0);
00540 etv.tv_sec += timeout;
00541 #else
00542 tv.tv_sec = timeout;
00543 tv.tv_usec = 0;
00544 #endif
00545 tvp = &tv;
00546 }
00547
00548 #ifdef Q_OS_UNIX
00549 int fd = KProcessController::theKProcessController->notifierFd();
00550 for(;;)
00551 {
00552 fd_set fds;
00553 FD_ZERO( &fds );
00554 FD_SET( fd, &fds );
00555
00556 #ifndef __linux__
00557 if (tvp)
00558 {
00559 gettimeofday(&tv, 0);
00560 timersub(&etv, &tv, &tv);
00561 if (tv.tv_sec < 0)
00562 tv.tv_sec = tv.tv_usec = 0;
00563 }
00564 #endif
00565
00566 switch( select( fd+1, &fds, 0, 0, tvp ) )
00567 {
00568 case -1:
00569 if( errno == EINTR )
00570 break;
00571
00572 case 0:
00573 KProcessController::theKProcessController->rescheduleCheck();
00574 return false;
00575 default:
00576 KProcessController::theKProcessController->unscheduleCheck();
00577 if (waitpid(pid_, &status, WNOHANG) != 0)
00578 {
00579 processHasExited(status);
00580 KProcessController::theKProcessController->rescheduleCheck();
00581 return true;
00582 }
00583 }
00584 }
00585 #endif //Q_OS_UNIX
00586 return false;
00587 }
00588
00589
00590
00591 bool KProcess::normalExit() const
00592 {
00593 return (pid_ != 0) && !runs && WIFEXITED(status);
00594 }
00595
00596
00597 bool KProcess::signalled() const
00598 {
00599 return (pid_ != 0) && !runs && WIFSIGNALED(status);
00600 }
00601
00602
00603 bool KProcess::coreDumped() const
00604 {
00605 #ifdef WCOREDUMP
00606 return signalled() && WCOREDUMP(status);
00607 #else
00608 return false;
00609 #endif
00610 }
00611
00612
00613 int KProcess::exitStatus() const
00614 {
00615 return WEXITSTATUS(status);
00616 }
00617
00618
00619 int KProcess::exitSignal() const
00620 {
00621 return WTERMSIG(status);
00622 }
00623
00624
00625 bool KProcess::writeStdin(const char *buffer, int buflen)
00626 {
00627
00628
00629
00630 if (input_data != 0)
00631 return false;
00632
00633 if (communication & Stdin) {
00634 input_data = buffer;
00635 input_sent = 0;
00636 input_total = buflen;
00637 innot->setEnabled(true);
00638 if (input_total)
00639 slotSendData(0);
00640 return true;
00641 } else
00642 return false;
00643 }
00644
00645 void KProcess::suspend()
00646 {
00647 if (outnot)
00648 outnot->setEnabled(false);
00649 }
00650
00651 void KProcess::resume()
00652 {
00653 if (outnot)
00654 outnot->setEnabled(true);
00655 }
00656
00657 bool KProcess::closeStdin()
00658 {
00659 if (communication & Stdin) {
00660 communication = (Communication) (communication & ~Stdin);
00661 delete innot;
00662 innot = 0;
00663 if (!(d->usePty & Stdin))
00664 close(in[1]);
00665 in[1] = -1;
00666 return true;
00667 } else
00668 return false;
00669 }
00670
00671 bool KProcess::closeStdout()
00672 {
00673 if (communication & Stdout) {
00674 communication = (Communication) (communication & ~Stdout);
00675 delete outnot;
00676 outnot = 0;
00677 if (!(d->usePty & Stdout))
00678 close(out[0]);
00679 out[0] = -1;
00680 return true;
00681 } else
00682 return false;
00683 }
00684
00685 bool KProcess::closeStderr()
00686 {
00687 if (communication & Stderr) {
00688 communication = (Communication) (communication & ~Stderr);
00689 delete errnot;
00690 errnot = 0;
00691 if (!(d->usePty & Stderr))
00692 close(err[0]);
00693 err[0] = -1;
00694 return true;
00695 } else
00696 return false;
00697 }
00698
00699 bool KProcess::closePty()
00700 {
00701 #ifdef Q_OS_UNIX
00702 if (d->pty && d->pty->masterFd() >= 0) {
00703 if (d->addUtmp)
00704 d->pty->logout();
00705 d->pty->close();
00706 return true;
00707 } else
00708 return false;
00709 #else
00710 return false;
00711 #endif
00712 }
00713
00714 void KProcess::closeAll()
00715 {
00716 closeStdin();
00717 closeStdout();
00718 closeStderr();
00719 closePty();
00720 }
00721
00723
00725
00726
00727
00728 void KProcess::slotChildOutput(int fdno)
00729 {
00730 if (!childOutput(fdno))
00731 closeStdout();
00732 }
00733
00734
00735 void KProcess::slotChildError(int fdno)
00736 {
00737 if (!childError(fdno))
00738 closeStderr();
00739 }
00740
00741
00742 void KProcess::slotSendData(int)
00743 {
00744 if (input_sent == input_total) {
00745 innot->setEnabled(false);
00746 input_data = 0;
00747 emit wroteStdin(this);
00748 } else {
00749 int result = ::write(in[1], input_data+input_sent, input_total-input_sent);
00750 if (result >= 0)
00751 {
00752 input_sent += result;
00753 }
00754 else if ((errno != EAGAIN) && (errno != EINTR))
00755 {
00756 kdDebug(175) << "Error writing to stdin of child process" << endl;
00757 closeStdin();
00758 }
00759 }
00760 }
00761
00762 void KProcess::setUseShell(bool useShell, const char *shell)
00763 {
00764 d->useShell = useShell;
00765 if (shell && *shell)
00766 d->shell = shell;
00767 else
00768
00769 #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__GNU__) && !defined(__DragonFly__)
00770
00771 if (!access( "/usr/xpg4/bin/sh", X_OK ))
00772 d->shell = "/usr/xpg4/bin/sh";
00773 else
00774
00775 if (!access( "/bin/ksh", X_OK ))
00776 d->shell = "/bin/ksh";
00777 else
00778
00779 if (!access( "/usr/ucb/sh", X_OK ))
00780 d->shell = "/usr/ucb/sh";
00781 else
00782 #endif
00783 d->shell = "/bin/sh";
00784 }
00785
00786 #ifdef Q_OS_UNIX
00787 void KProcess::setUsePty(Communication usePty, bool addUtmp)
00788 {
00789 d->usePty = usePty;
00790 d->addUtmp = addUtmp;
00791 if (usePty) {
00792 if (!d->pty)
00793 d->pty = new KPty;
00794 } else {
00795 delete d->pty;
00796 d->pty = 0;
00797 }
00798 }
00799
00800 KPty *KProcess::pty() const
00801 {
00802 return d->pty;
00803 }
00804 #endif //Q_OS_UNIX
00805
00806 QString KProcess::quote(const QString &arg)
00807 {
00808 QChar q('\'');
00809 return QString(arg).replace(q, "'\\''").prepend(q).append(q);
00810 }
00811
00812
00814
00816
00817
00818 void KProcess::processHasExited(int state)
00819 {
00820
00821
00822 status = state;
00823 runs = false;
00824
00825 commClose();
00826
00827 if (run_mode != DontCare)
00828 emit processExited(this);
00829 }
00830
00831
00832
00833 int KProcess::childOutput(int fdno)
00834 {
00835 if (communication & NoRead) {
00836 int len = -1;
00837 emit receivedStdout(fdno, len);
00838 errno = 0;
00839 return len;
00840 }
00841 else
00842 {
00843 char buffer[1025];
00844 int len;
00845
00846 len = ::read(fdno, buffer, 1024);
00847
00848 if (len > 0) {
00849 buffer[len] = 0;
00850 emit receivedStdout(this, buffer, len);
00851 }
00852 return len;
00853 }
00854 }
00855
00856 int KProcess::childError(int fdno)
00857 {
00858 char buffer[1025];
00859 int len;
00860
00861 len = ::read(fdno, buffer, 1024);
00862
00863 if (len > 0) {
00864 buffer[len] = 0;
00865 emit receivedStderr(this, buffer, len);
00866 }
00867 return len;
00868 }
00869
00870
00871 int KProcess::setupCommunication(Communication comm)
00872 {
00873 #ifdef Q_OS_UNIX
00874
00875 if (d->usePty)
00876 {
00877
00878 if (!(~(comm & d->usePty) & (Stdout | Stderr))) {
00879 kdWarning(175) << "Invalid usePty/communication combination (" << d->usePty << "/" << comm << ")" << endl;
00880 return 0;
00881 }
00882 if (!d->pty->open())
00883 return 0;
00884
00885 int rcomm = comm & d->usePty;
00886 int mfd = d->pty->masterFd();
00887 if (rcomm & Stdin)
00888 in[1] = mfd;
00889 if (rcomm & Stdout)
00890 out[0] = mfd;
00891 if (rcomm & Stderr)
00892 err[0] = mfd;
00893 }
00894
00895 communication = comm;
00896
00897 comm = (Communication) (comm & ~d->usePty);
00898 if (comm & Stdin) {
00899 if (socketpair(AF_UNIX, SOCK_STREAM, 0, in))
00900 goto fail0;
00901 fcntl(in[0], F_SETFD, FD_CLOEXEC);
00902 fcntl(in[1], F_SETFD, FD_CLOEXEC);
00903 }
00904 if (comm & Stdout) {
00905 if (socketpair(AF_UNIX, SOCK_STREAM, 0, out))
00906 goto fail1;
00907 fcntl(out[0], F_SETFD, FD_CLOEXEC);
00908 fcntl(out[1], F_SETFD, FD_CLOEXEC);
00909 }
00910 if (comm & Stderr) {
00911 if (socketpair(AF_UNIX, SOCK_STREAM, 0, err))
00912 goto fail2;
00913 fcntl(err[0], F_SETFD, FD_CLOEXEC);
00914 fcntl(err[1], F_SETFD, FD_CLOEXEC);
00915 }
00916 return 1;
00917 fail2:
00918 if (comm & Stdout)
00919 {
00920 close(out[0]);
00921 close(out[1]);
00922 out[0] = out[1] = -1;
00923 }
00924 fail1:
00925 if (comm & Stdin)
00926 {
00927 close(in[0]);
00928 close(in[1]);
00929 in[0] = in[1] = -1;
00930 }
00931 fail0:
00932 communication = NoCommunication;
00933 #endif //Q_OS_UNIX
00934 return 0;
00935 }
00936
00937
00938
00939 int KProcess::commSetupDoneP()
00940 {
00941 int rcomm = communication & ~d->usePty;
00942 if (rcomm & Stdin)
00943 close(in[0]);
00944 if (rcomm & Stdout)
00945 close(out[1]);
00946 if (rcomm & Stderr)
00947 close(err[1]);
00948 in[0] = out[1] = err[1] = -1;
00949
00950
00951 if (run_mode != NotifyOnExit && run_mode != OwnGroup)
00952 return 1;
00953
00954 if (communication & Stdin) {
00955 fcntl(in[1], F_SETFL, O_NONBLOCK | fcntl(in[1], F_GETFL));
00956 innot = new QSocketNotifier(in[1], QSocketNotifier::Write, this);
00957 Q_CHECK_PTR(innot);
00958 innot->setEnabled(false);
00959 QObject::connect(innot, SIGNAL(activated(int)),
00960 this, SLOT(slotSendData(int)));
00961 }
00962
00963 if (communication & Stdout) {
00964 outnot = new QSocketNotifier(out[0], QSocketNotifier::Read, this);
00965 Q_CHECK_PTR(outnot);
00966 QObject::connect(outnot, SIGNAL(activated(int)),
00967 this, SLOT(slotChildOutput(int)));
00968 if (communication & NoRead)
00969 suspend();
00970 }
00971
00972 if (communication & Stderr) {
00973 errnot = new QSocketNotifier(err[0], QSocketNotifier::Read, this );
00974 Q_CHECK_PTR(errnot);
00975 QObject::connect(errnot, SIGNAL(activated(int)),
00976 this, SLOT(slotChildError(int)));
00977 }
00978
00979 return 1;
00980 }
00981
00982
00983
00984 int KProcess::commSetupDoneC()
00985 {
00986 int ok = 1;
00987 #ifdef Q_OS_UNIX
00988
00989 if (d->usePty & Stdin) {
00990 if (dup2(d->pty->slaveFd(), STDIN_FILENO) < 0) ok = 0;
00991 } else if (communication & Stdin) {
00992 if (dup2(in[0], STDIN_FILENO) < 0) ok = 0;
00993 } else {
00994 int null_fd = open( "/dev/null", O_RDONLY );
00995 if (dup2( null_fd, STDIN_FILENO ) < 0) ok = 0;
00996 close( null_fd );
00997 }
00998 struct linger so;
00999 memset(&so, 0, sizeof(so));
01000 if (d->usePty & Stdout) {
01001 if (dup2(d->pty->slaveFd(), STDOUT_FILENO) < 0) ok = 0;
01002 } else if (communication & Stdout) {
01003 if (dup2(out[1], STDOUT_FILENO) < 0 ||
01004 setsockopt(out[1], SOL_SOCKET, SO_LINGER, (char *)&so, sizeof(so)))
01005 ok = 0;
01006 if (communication & MergedStderr) {
01007 if (dup2(out[1], STDERR_FILENO) < 0)
01008 ok = 0;
01009 }
01010 }
01011 if (d->usePty & Stderr) {
01012 if (dup2(d->pty->slaveFd(), STDERR_FILENO) < 0) ok = 0;
01013 } else if (communication & Stderr) {
01014 if (dup2(err[1], STDERR_FILENO) < 0 ||
01015 setsockopt(err[1], SOL_SOCKET, SO_LINGER, (char *)&so, sizeof(so)))
01016 ok = 0;
01017 }
01018
01019
01020
01021
01022 if (d->usePty) {
01023 d->pty->setCTty();
01024 if (d->addUtmp)
01025 d->pty->login(KUser(KUser::UseRealUserID).loginName().local8Bit().data(), getenv("DISPLAY"));
01026 }
01027 #endif //Q_OS_UNIX
01028
01029 return ok;
01030 }
01031
01032
01033
01034 void KProcess::commClose()
01035 {
01036 closeStdin();
01037
01038 #ifdef Q_OS_UNIX
01039 if (pid_) {
01040
01041
01042
01043
01044 int notfd = KProcessController::theKProcessController->notifierFd();
01045
01046 while ((communication & (Stdout | Stderr)) || runs) {
01047 fd_set rfds;
01048 FD_ZERO(&rfds);
01049 struct timeval timeout, *p_timeout;
01050
01051 int max_fd = 0;
01052 if (communication & Stdout) {
01053 FD_SET(out[0], &rfds);
01054 max_fd = out[0];
01055 }
01056 if (communication & Stderr) {
01057 FD_SET(err[0], &rfds);
01058 if (err[0] > max_fd)
01059 max_fd = err[0];
01060 }
01061 if (runs) {
01062 FD_SET(notfd, &rfds);
01063 if (notfd > max_fd)
01064 max_fd = notfd;
01065
01066
01067 p_timeout = 0;
01068 } else {
01069
01070
01071 timeout.tv_sec = timeout.tv_usec = 0;
01072 p_timeout = &timeout;
01073 }
01074
01075 int fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout);
01076 if (fds_ready < 0) {
01077 if (errno == EINTR)
01078 continue;
01079 break;
01080 } else if (!fds_ready)
01081 break;
01082
01083 if ((communication & Stdout) && FD_ISSET(out[0], &rfds))
01084 slotChildOutput(out[0]);
01085
01086 if ((communication & Stderr) && FD_ISSET(err[0], &rfds))
01087 slotChildError(err[0]);
01088
01089 if (runs && FD_ISSET(notfd, &rfds)) {
01090 runs = false;
01091 return;
01092 }
01093 }
01094 }
01095 #endif //Q_OS_UNIX
01096
01097 closeStdout();
01098 closeStderr();
01099
01100 closePty();
01101 }
01102
01103
01104 void KProcess::virtual_hook( int, void* )
01105 { }
01106
01107
01109
01111
01112 KShellProcess::KShellProcess(const char *shellname):
01113 KProcess()
01114 {
01115 setUseShell( true, shellname ? shellname : getenv("SHELL") );
01116 }
01117
01118 KShellProcess::~KShellProcess() {
01119 }
01120
01121 QString KShellProcess::quote(const QString &arg)
01122 {
01123 return KProcess::quote(arg);
01124 }
01125
01126 bool KShellProcess::start(RunMode runmode, Communication comm)
01127 {
01128 return KProcess::start(runmode, comm);
01129 }
01130
01131 void KShellProcess::virtual_hook( int id, void* data )
01132 { KProcess::virtual_hook( id, data ); }
01133
01134 #include "kprocess.moc"