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